From cb5814a5ce42d22b3e1a96bbc61db557d5d97c74 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Tue, 17 Dec 2024 16:42:21 +0200 Subject: [PATCH] fs: rework sysfs --- Cargo.lock | 1 + kernel/driver/block/ahci/src/lib.rs | 2 +- kernel/lib/device-tree/Cargo.toml | 1 + kernel/lib/device-tree/src/tree.rs | 7 + kernel/lib/device-tree/src/util.rs | 40 ++++ kernel/lib/memtables/src/aarch64.rs | 2 +- kernel/libk/src/debug.rs | 97 +++++++++- kernel/libk/src/device/manager.rs | 2 +- kernel/libk/src/{ => fs}/devfs.rs | 0 kernel/libk/src/fs/mod.rs | 2 + kernel/libk/src/fs/sysfs/attribute/bytes.rs | 128 ++++++++++++ kernel/libk/src/fs/sysfs/attribute/mod.rs | 17 ++ kernel/libk/src/fs/sysfs/attribute/string.rs | 193 +++++++++++++++++++ kernel/libk/src/fs/sysfs/mod.rs | 30 +++ kernel/libk/src/fs/sysfs/object.rs | 69 +++++++ kernel/libk/src/lib.rs | 2 +- kernel/libk/src/vfs/node/mod.rs | 28 ++- kernel/src/arch/aarch64/boot/mod.rs | 6 +- kernel/src/arch/aarch64/mod.rs | 3 + kernel/src/device/serial/pl011.rs | 2 +- kernel/src/fs/mod.rs | 5 +- kernel/src/fs/pseudo.rs | 2 +- kernel/src/fs/sysfs.rs | 112 ----------- kernel/src/init.rs | 2 +- kernel/src/main.rs | 47 ++++- 25 files changed, 662 insertions(+), 138 deletions(-) rename kernel/libk/src/{ => fs}/devfs.rs (100%) create mode 100644 kernel/libk/src/fs/mod.rs create mode 100644 kernel/libk/src/fs/sysfs/attribute/bytes.rs create mode 100644 kernel/libk/src/fs/sysfs/attribute/mod.rs create mode 100644 kernel/libk/src/fs/sysfs/attribute/string.rs create mode 100644 kernel/libk/src/fs/sysfs/mod.rs create mode 100644 kernel/libk/src/fs/sysfs/object.rs delete mode 100644 kernel/src/fs/sysfs.rs diff --git a/Cargo.lock b/Cargo.lock index 4662d5f9..d34d5984 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,6 +458,7 @@ dependencies = [ "device-api", "discrete_range_map", "fdt-rs", + "libk", "libk-mm", "libk-util", "log", diff --git a/kernel/driver/block/ahci/src/lib.rs b/kernel/driver/block/ahci/src/lib.rs index 188210ec..25bfd934 100644 --- a/kernel/driver/block/ahci/src/lib.rs +++ b/kernel/driver/block/ahci/src/lib.rs @@ -12,7 +12,7 @@ use device_api::{ interrupt::{InterruptAffinity, InterruptHandler}, }; use error::AhciError; -use libk::{devfs, device::manager::probe_partitions, task::runtime}; +use libk::{device::manager::probe_partitions, fs::devfs, task::runtime}; use libk_mm::{address::AsPhysicalAddress, device::DeviceMemoryIo, PageBox}; use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; use port::AhciPort; diff --git a/kernel/lib/device-tree/Cargo.toml b/kernel/lib/device-tree/Cargo.toml index eba5fa77..b9f5c1fc 100644 --- a/kernel/lib/device-tree/Cargo.toml +++ b/kernel/lib/device-tree/Cargo.toml @@ -10,6 +10,7 @@ yggdrasil-abi.workspace = true device-api = { path = "../device-api", features = ["derive"] } libk-mm.workspace = true libk-util.workspace = true +libk.workspace = true fdt-rs.workspace = true log.workspace = true diff --git a/kernel/lib/device-tree/src/tree.rs b/kernel/lib/device-tree/src/tree.rs index 77327424..5bae5cce 100644 --- a/kernel/lib/device-tree/src/tree.rs +++ b/kernel/lib/device-tree/src/tree.rs @@ -70,6 +70,11 @@ impl<'a> DeviceTree<'a> { self.tree.totalsize() } + /// Returns the underlying FDT blob bytes + pub fn as_bytes(&self) -> &'a [u8] { + self.tree.buf() + } + /// Returns the root node of this device tree pub fn root(&self) -> TNode { self.index.root() @@ -171,3 +176,5 @@ impl<'a> DeviceTree<'a> { DevTree::read_totalsize(header).map_err(|_| Error::InvalidArgument) } } + +unsafe impl Sync for DeviceTree<'_> {} diff --git a/kernel/lib/device-tree/src/util.rs b/kernel/lib/device-tree/src/util.rs index 7bd9eedd..6b11fa1e 100644 --- a/kernel/lib/device-tree/src/util.rs +++ b/kernel/lib/device-tree/src/util.rs @@ -1,5 +1,13 @@ //! Utility functions for device tree handling use fdt_rs::index::iters::DevTreeIndexNodeSiblingIter; +use libk::{ + error::Error, + fs::sysfs::{ + self, + attribute::{BytesAttribute, BytesAttributeOps}, + object::KObject, + }, +}; use libk_mm::{address::PhysicalAddress, phys::PhysicalMemoryRegion}; use crate::{node::DeviceTreeNodeExt, property::DeviceTreePropertyRead, tree::DeviceTree}; @@ -44,3 +52,35 @@ impl Iterator for DeviceTreeMemoryRegionIter<'_> { } } } + +/// Registers sysfs objects related to the device tree +pub fn create_sysfs_nodes(dt: &'static DeviceTree) { + struct Raw; + + impl BytesAttributeOps for Raw { + type Data = &'static DeviceTree<'static>; + const NAME: &'static str = "raw"; + + fn read(state: &Self::Data, pos: usize, buffer: &mut [u8]) -> Result { + let data = state.as_bytes(); + if pos >= data.len() { + return Ok(0); + } + let amount = (data.len() - pos).min(buffer.len()); + buffer[..amount].copy_from_slice(&data[pos..pos + amount]); + Ok(amount) + } + + fn size(state: &Self::Data) -> usize { + state.size() + } + } + + if let Some(device) = sysfs::device() { + let object = KObject::new(dt); + + object.add_attribute(BytesAttribute::from(Raw)).ok(); + + device.add_object("device-tree", object).ok(); + } +} diff --git a/kernel/lib/memtables/src/aarch64.rs b/kernel/lib/memtables/src/aarch64.rs index 5adab8bc..764ae981 100644 --- a/kernel/lib/memtables/src/aarch64.rs +++ b/kernel/lib/memtables/src/aarch64.rs @@ -2,7 +2,7 @@ use bytemuck::{Pod, Zeroable}; use crate::RawTable; -pub const KERNEL_L3_COUNT: usize = 4; +pub const KERNEL_L3_COUNT: usize = 8; #[derive(Clone, Copy, Pod, Zeroable)] #[repr(C)] diff --git a/kernel/libk/src/debug.rs b/kernel/libk/src/debug.rs index acf1e938..448eee82 100644 --- a/kernel/libk/src/debug.rs +++ b/kernel/libk/src/debug.rs @@ -5,10 +5,15 @@ use core::{ fmt::{self, Arguments}, + str::FromStr, sync::atomic::{AtomicBool, Ordering}, }; -use alloc::sync::Arc; +use alloc::{ + format, + string::{String, ToString}, + sync::Arc, +}; use libk_util::{ ring::RingBuffer, sync::{ @@ -19,7 +24,14 @@ use libk_util::{ }; use yggdrasil_abi::error::Error; -use crate::task::{process::Process, thread::Thread}; +use crate::{ + fs::sysfs::{ + self, + attribute::{StringAttribute, StringAttributeOps}, + object::KObject, + }, + task::{process::Process, thread::Thread}, +}; const MAX_DEBUG_SINKS: usize = 8; const RING_LOGGER_CAPACITY: usize = 65536; @@ -116,6 +128,12 @@ impl DebugSinkWrapper { Self::Arc(level, _) => *level, } } + + pub fn set_level(&mut self, target: LogLevel) { + match self { + Self::Arc(level, _) => *level = target, + } + } } impl log::Log for DebugSinkWrapper { @@ -315,9 +333,51 @@ static DEBUG_SINKS: IrqSafeRwLock Arc> { + struct Level; + + impl StringAttributeOps for Level { + type Data = usize; + const NAME: &'static str = "level"; + const LIMIT: usize = 16; + const WRITEABLE: bool = true; + + fn read(state: &Self::Data) -> Result { + let sinks = DEBUG_SINKS.read(); + let sink = sinks.get(*state).ok_or(Error::InvalidFile)?; + Ok(sink.level().to_string()) + } + + fn write(state: &Self::Data, value: &str) -> Result<(), Error> { + let level = LogLevel::from_str(value)?; + let mut sinks = DEBUG_SINKS.write(); + let sink = sinks.get_mut(*state).ok_or(Error::InvalidFile)?; + sink.set_level(level); + Ok(()) + } + } + + let object = KObject::new(index); + + object.add_attribute(StringAttribute::from(Level)).ok(); + + object +} + /// Adds a debugging output sink pub fn add_sink(sink: Arc, level: LogLevel) { - DEBUG_SINKS.write().push(DebugSinkWrapper::Arc(level, sink)); + let index = { + let mut sinks = DEBUG_SINKS.write(); + let index = sinks.len(); + sinks.push(DebugSinkWrapper::Arc(level, sink.clone())); + index + }; + + if let Some(debug) = sysfs::debug() { + debug + .add_object(format!("{index}"), make_sysfs_sink_object(index)) + .ok(); + } } pub fn add_serial_sink(sink: Arc, level: LogLevel) { @@ -349,3 +409,34 @@ pub fn init() { .map(|_| log::set_max_level(log::LevelFilter::Trace)) .ok(); } + +impl fmt::Display for LogLevel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let level = match self { + Self::Trace => "trace", + Self::Debug => "debug", + Self::Info => "info", + Self::Warning => "warn", + Self::Error => "error", + Self::Fatal => "fatal", + }; + + f.write_str(level) + } +} + +impl FromStr for LogLevel { + type Err = Error; + + fn from_str(s: &str) -> Result { + match s { + "trace" | "t" => Ok(Self::Trace), + "debug" | "d" => Ok(Self::Debug), + "info" | "i" => Ok(Self::Info), + "warn" | "w" => Ok(Self::Warning), + "error" | "e" => Ok(Self::Error), + "fatal" | "f" => Ok(Self::Fatal), + _ => Err(Error::InvalidArgument), + } + } +} diff --git a/kernel/libk/src/device/manager.rs b/kernel/libk/src/device/manager.rs index 0023e484..42400d1f 100644 --- a/kernel/libk/src/device/manager.rs +++ b/kernel/libk/src/device/manager.rs @@ -10,7 +10,7 @@ use yggdrasil_abi::error::Error; use crate::{ debug::{self, DebugSink, LogLevel}, - devfs, + fs::devfs, vfs::NodeRef, }; diff --git a/kernel/libk/src/devfs.rs b/kernel/libk/src/fs/devfs.rs similarity index 100% rename from kernel/libk/src/devfs.rs rename to kernel/libk/src/fs/devfs.rs diff --git a/kernel/libk/src/fs/mod.rs b/kernel/libk/src/fs/mod.rs new file mode 100644 index 00000000..518842f5 --- /dev/null +++ b/kernel/libk/src/fs/mod.rs @@ -0,0 +1,2 @@ +pub mod devfs; +pub mod sysfs; diff --git a/kernel/libk/src/fs/sysfs/attribute/bytes.rs b/kernel/libk/src/fs/sysfs/attribute/bytes.rs new file mode 100644 index 00000000..86c08c6f --- /dev/null +++ b/kernel/libk/src/fs/sysfs/attribute/bytes.rs @@ -0,0 +1,128 @@ +use core::{any::Any, marker::PhantomData}; + +use alloc::sync::Arc; +use yggdrasil_abi::{ + error::Error, + io::{FileMode, OpenOptions}, +}; + +use crate::{ + fs::sysfs::object::KObject, + vfs::{CommonImpl, InstanceData, Node, NodeFlags, NodeRef, RegularImpl}, +}; + +use super::Attribute; + +pub trait BytesAttributeOps: Send + Sync + 'static { + type Data: Send + 'static = (); + const NAME: &'static str; + const WRITEABLE: bool = false; + + fn read(state: &Self::Data, pos: usize, buffer: &mut [u8]) -> Result { + let _ = state; + let _ = pos; + let _ = buffer; + Err(Error::NotImplemented) + } + + fn write(state: &Self::Data, pos: usize, buffer: &[u8]) -> Result { + let _ = state; + let _ = pos; + let _ = buffer; + Err(Error::ReadOnly) + } + + fn size(state: &Self::Data) -> usize { + let _ = state; + 0 + } +} + +pub struct BytesAttribute(PhantomData); + +struct BytesAttributeNode { + object: Arc>, + _pd: PhantomData, +} + +impl CommonImpl for BytesAttributeNode { + fn size(&self, _node: &NodeRef) -> Result { + Ok(V::size(&self.object.data) as u64) + } + + fn as_any(&self) -> &dyn Any { + self as _ + } +} + +impl RegularImpl for BytesAttributeNode { + fn open( + &self, + _node: &NodeRef, + opts: OpenOptions, + ) -> Result<(u64, Option), Error> { + if opts.contains(OpenOptions::WRITE) && !V::WRITEABLE { + return Err(Error::ReadOnly); + } + + Ok((0, None)) + } + + fn close(&self, _node: &NodeRef, _instance: Option<&InstanceData>) -> Result<(), Error> { + Ok(()) + } + + fn read( + &self, + _node: &NodeRef, + _instance: Option<&InstanceData>, + pos: u64, + buf: &mut [u8], + ) -> Result { + let pos = pos.try_into().map_err(|_| Error::InvalidArgument)?; + V::read(&self.object.data, pos, buf) + } + + fn write( + &self, + _node: &NodeRef, + _instance: Option<&InstanceData>, + pos: u64, + buf: &[u8], + ) -> Result { + let pos = pos.try_into().map_err(|_| Error::InvalidArgument)?; + V::write(&self.object.data, pos, buf) + } + + fn truncate(&self, _node: &NodeRef, _new_size: u64) -> Result<(), Error> { + Ok(()) + } +} + +impl From for BytesAttribute { + fn from(_value: V) -> Self { + Self(PhantomData) + } +} + +impl Attribute for BytesAttribute { + fn instantiate(&self, parent: &Arc>) -> Result { + let mode = match V::WRITEABLE { + false => FileMode::new(0o444), + true => FileMode::new(0o644), + }; + + Ok(Node::regular_kernel( + BytesAttributeNode { + object: parent.clone(), + _pd: PhantomData::, + }, + NodeFlags::IN_MEMORY_PROPS, + mode, + )) + } + + fn name(&self) -> &str { + V::NAME + } +} diff --git a/kernel/libk/src/fs/sysfs/attribute/mod.rs b/kernel/libk/src/fs/sysfs/attribute/mod.rs new file mode 100644 index 00000000..cecbd61e --- /dev/null +++ b/kernel/libk/src/fs/sysfs/attribute/mod.rs @@ -0,0 +1,17 @@ +use alloc::sync::Arc; +use yggdrasil_abi::error::Error; + +use crate::vfs::NodeRef; + +use super::object::KObject; + +mod bytes; +mod string; + +pub trait Attribute: Sync + Send { + fn instantiate(&self, parent: &Arc>) -> Result; + fn name(&self) -> &str; +} + +pub use bytes::{BytesAttribute, BytesAttributeOps}; +pub use string::{StringAttribute, StringAttributeOps}; diff --git a/kernel/libk/src/fs/sysfs/attribute/string.rs b/kernel/libk/src/fs/sysfs/attribute/string.rs new file mode 100644 index 00000000..9bc160a5 --- /dev/null +++ b/kernel/libk/src/fs/sysfs/attribute/string.rs @@ -0,0 +1,193 @@ +use core::{ + any::Any, + marker::PhantomData, + sync::atomic::{AtomicBool, Ordering}, +}; + +use alloc::{string::String, sync::Arc, vec::Vec}; +use libk_util::sync::spin_rwlock::IrqSafeRwLock; +use yggdrasil_abi::{ + error::Error, + io::{FileMode, OpenOptions}, +}; + +use crate::{ + fs::sysfs::object::KObject, + vfs::{CommonImpl, InstanceData, Node, NodeFlags, NodeRef, RegularImpl}, +}; + +use super::Attribute; + +pub trait StringAttributeOps: Sync + Send + 'static { + type Data: Send + 'static = (); + + const WRITEABLE: bool = false; + const NAME: &'static str; + const LIMIT: usize = 4096; + + fn read(state: &Self::Data) -> Result { + let _ = state; + Err(Error::NotImplemented) + } + fn write(state: &Self::Data, value: &str) -> Result<(), Error> { + let _ = state; + let _ = value; + Err(Error::ReadOnly) + } +} + +pub struct StringAttribute(PhantomData); + +struct StringAttributeNode { + object: Arc>, + _pd: PhantomData, +} + +struct StringAttributeState { + value: IrqSafeRwLock>, + modified: AtomicBool, +} + +impl CommonImpl for StringAttributeNode { + fn size(&self, _node: &NodeRef) -> Result { + Ok(0) + } + + fn as_any(&self) -> &dyn Any { + self as _ + } +} + +impl RegularImpl for StringAttributeNode { + fn open( + &self, + _node: &NodeRef, + opts: OpenOptions, + ) -> Result<(u64, Option), Error> { + if opts.contains(OpenOptions::WRITE) && !V::WRITEABLE { + return Err(Error::ReadOnly); + } + + let mut value = V::read(self.object.data())?.into_bytes(); + value.push(b'\n'); + + let instance = StringAttributeState { + value: IrqSafeRwLock::new(value), + modified: AtomicBool::new(false), + }; + + Ok((0, Some(Arc::new(instance)))) + } + + fn close(&self, _node: &NodeRef, instance: Option<&InstanceData>) -> Result<(), Error> { + if V::WRITEABLE { + let instance = instance.ok_or(Error::InvalidFile)?; + let instance = instance + .downcast_ref::() + .ok_or(Error::InvalidFile)?; + + if instance.modified.load(Ordering::Acquire) { + let value = instance.value.read(); + let value_str = + core::str::from_utf8(&value[..]).map_err(|_| Error::InvalidArgument)?; + + // Trim whitespace and newlines + V::write(&self.object.data, value_str.trim())?; + } + } + + Ok(()) + } + + fn read( + &self, + _node: &NodeRef, + instance: Option<&InstanceData>, + pos: u64, + buf: &mut [u8], + ) -> Result { + let instance = instance.ok_or(Error::InvalidFile)?; + let instance = instance + .downcast_ref::() + .ok_or(Error::InvalidFile)?; + + let value = instance.value.read(); + let len = value.len(); + if pos >= len as u64 { + return Ok(0); + } + let pos = pos as usize; + let amount = (len - pos).min(buf.len()); + buf[..amount].copy_from_slice(&value[pos..pos + amount]); + + Ok(amount) + } + + fn write( + &self, + _node: &NodeRef, + instance: Option<&InstanceData>, + pos: u64, + buf: &[u8], + ) -> Result { + if !V::WRITEABLE { + return Err(Error::InvalidFile); + } + let instance = instance.ok_or(Error::InvalidFile)?; + let instance = instance + .downcast_ref::() + .ok_or(Error::InvalidFile)?; + + let mut value = instance.value.write(); + + let pos: usize = pos.try_into().map_err(|_| Error::InvalidFile)?; + if pos > value.len() { + return Err(Error::InvalidArgument); + } + if pos + buf.len() > V::LIMIT { + return Err(Error::InvalidArgument); + } + + let amount_copy = (value.len() - pos).min(buf.len()); + + value[pos..pos + amount_copy].copy_from_slice(&buf[..amount_copy]); + if amount_copy < buf.len() { + value.extend_from_slice(&buf[amount_copy..]); + } + instance.modified.store(true, Ordering::Release); + + Ok(buf.len()) + } + + fn truncate(&self, _node: &NodeRef, _new_size: u64) -> Result<(), Error> { + Ok(()) + } +} + +impl From for StringAttribute { + fn from(_value: V) -> Self { + Self(PhantomData) + } +} + +impl Attribute for StringAttribute { + fn instantiate(&self, parent: &Arc>) -> Result, Error> { + let mode = match V::WRITEABLE { + false => FileMode::new(0o444), + true => FileMode::new(0o644), + }; + + Ok(Node::regular_kernel( + StringAttributeNode { + object: parent.clone(), + _pd: PhantomData::, + }, + NodeFlags::IN_MEMORY_PROPS, + mode, + )) + } + + fn name(&self) -> &str { + V::NAME + } +} diff --git a/kernel/libk/src/fs/sysfs/mod.rs b/kernel/libk/src/fs/sysfs/mod.rs new file mode 100644 index 00000000..97e440ee --- /dev/null +++ b/kernel/libk/src/fs/sysfs/mod.rs @@ -0,0 +1,30 @@ +use alloc::sync::Arc; +use libk_util::OneTimeInit; +use object::KObject; + +use crate::vfs::NodeRef; + +pub mod attribute; +pub mod object; + +static ROOT: OneTimeInit = OneTimeInit::new(); + +pub fn root() -> &'static NodeRef { + ROOT.get() +} + +pub fn kernel() -> Option<&'static Arc>> { + object::KERNEL_OBJECT.try_get() +} + +pub fn debug() -> Option<&'static Arc>> { + object::DEBUG_OBJECT.try_get() +} + +pub fn device() -> Option<&'static Arc>> { + object::DEVICE_OBJECT.try_get() +} + +pub fn init() { + ROOT.init(object::setup_fixed_objects()); +} diff --git a/kernel/libk/src/fs/sysfs/object.rs b/kernel/libk/src/fs/sysfs/object.rs new file mode 100644 index 00000000..84e31f5f --- /dev/null +++ b/kernel/libk/src/fs/sysfs/object.rs @@ -0,0 +1,69 @@ +use alloc::{string::String, sync::Arc}; +use libk_util::OneTimeInit; +use yggdrasil_abi::{error::Error, io::FileMode}; + +use crate::vfs::{impls::MemoryDirectory, Node, NodeFlags}; + +use super::attribute::Attribute; + +pub struct KObject { + pub(super) data: D, + pub(super) node: Arc, +} + +impl KObject { + pub fn new(data: D) -> Arc { + let node = Node::directory_kernel( + MemoryDirectory, + NodeFlags::IN_MEMORY_SIZE | NodeFlags::IN_MEMORY_PROPS, + FileMode::new(0o555), + ); + Arc::new(Self { data, node }) + } + + pub fn add_attribute>(self: &Arc, attribute: A) -> Result<(), Error> { + let node = attribute.instantiate(self)?; + self.node.add_child(attribute.name(), node)?; + Ok(()) + } + + pub fn add_object, T>( + &self, + name: S, + child: Arc>, + ) -> Result<(), Error> { + self.node.add_child(name, child.node.clone()) + } + + pub(super) fn data(&self) -> &D { + &self.data + } +} + +unsafe impl Send for KObject {} +unsafe impl Sync for KObject {} + +// Static, fixed objects +// `/` +pub static ROOT_OBJECT: OneTimeInit>> = OneTimeInit::new(); +// `/kernel` +pub static KERNEL_OBJECT: OneTimeInit>> = OneTimeInit::new(); +// `/device` +pub static DEVICE_OBJECT: OneTimeInit>> = OneTimeInit::new(); +// `/debug` +pub static DEBUG_OBJECT: OneTimeInit>> = OneTimeInit::new(); + +fn setup_fixed_object(root: &Arc>, obj: &OneTimeInit>>, name: &str) { + let obj = obj.init(KObject::new(())); + root.add_object(name, obj.clone()).ok(); +} + +pub fn setup_fixed_objects() -> Arc { + let root = ROOT_OBJECT.init(KObject::new(())); + + setup_fixed_object(root, &KERNEL_OBJECT, "kernel"); + setup_fixed_object(root, &DEVICE_OBJECT, "device"); + setup_fixed_object(root, &DEBUG_OBJECT, "debug"); + + root.node.clone() +} diff --git a/kernel/libk/src/lib.rs b/kernel/libk/src/lib.rs index ad6da6ba..9b09f9bc 100644 --- a/kernel/libk/src/lib.rs +++ b/kernel/libk/src/lib.rs @@ -36,8 +36,8 @@ pub mod task; pub mod arch; pub mod debug; -pub mod devfs; pub mod device; +pub mod fs; pub mod module; pub mod random; pub mod time; diff --git a/kernel/libk/src/vfs/node/mod.rs b/kernel/libk/src/vfs/node/mod.rs index 706449b3..ae6162f8 100644 --- a/kernel/libk/src/vfs/node/mod.rs +++ b/kernel/libk/src/vfs/node/mod.rs @@ -175,14 +175,30 @@ impl Node { (master, slave) } - /// Creates a new directory node with given [DirectoryImpl] - pub fn directory(data: T, flags: NodeFlags) -> NodeRef { + /// Creates a new directory node with given [DirectoryImpl] and permissions + pub fn directory_kernel( + data: T, + flags: NodeFlags, + mode: FileMode, + ) -> NodeRef { let data = NodeImpl::Directory(DirectoryData { imp: Box::new(data), mountpoint: IrqSafeSpinlock::new(None), children: IrqSafeSpinlock::new(Vec::new()), }); - Self::new(data, flags, Metadata::default_dir()) + Self::new( + data, + flags, + Metadata { + mode, + ..Metadata::default_dir() + }, + ) + } + + /// Creates a new directory node with given [DirectoryImpl] + pub fn directory(data: T, flags: NodeFlags) -> NodeRef { + Self::directory_kernel(data, flags, FileMode::default_dir()) } /// Creates a new file node with given [RegularImpl] and permissions @@ -196,11 +212,7 @@ impl Node { flags, Metadata { mode, - uid: UserId::root(), - gid: GroupId::root(), - block_size: 0, - block_count: 0, - inode: None, + ..Metadata::default_file() }, ) } diff --git a/kernel/src/arch/aarch64/boot/mod.rs b/kernel/src/arch/aarch64/boot/mod.rs index 5844aa79..2e86625a 100644 --- a/kernel/src/arch/aarch64/boot/mod.rs +++ b/kernel/src/arch/aarch64/boot/mod.rs @@ -13,7 +13,10 @@ use kernel_arch_aarch64::{ mem::{self, table::L3}, CPU_COUNT, }; -use libk::{devfs, task::runtime}; +use libk::{ + fs::{devfs, sysfs}, + task::runtime, +}; use libk_mm::{ address::{PhysicalAddress, Virtualize}, phys, @@ -121,6 +124,7 @@ unsafe extern "C" fn __aarch64_bsp_upper_entry(dtb: PhysicalAddress) -> ! { exception::init_exceptions(); + sysfs::init(); devfs::init(); runtime::init_task_queue(); diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index 4d38aeef..886afc0e 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -284,6 +284,9 @@ impl AArch64 { let dt = self.dt.get(); + // Create device tree sysfs nodes + device_tree::util::create_sysfs_nodes(dt); + let (machine_compatible, machine_name) = Self::machine_name(dt); if let Some(compatible) = machine_compatible { diff --git a/kernel/src/device/serial/pl011.rs b/kernel/src/device/serial/pl011.rs index 882d523d..7c90c736 100644 --- a/kernel/src/device/serial/pl011.rs +++ b/kernel/src/device/serial/pl011.rs @@ -158,7 +158,7 @@ impl Device for Pl011 { DEVICE_REGISTRY .serial_terminal - .register(terminal.clone(), Some((self.clone(), LogLevel::Debug))) + .register(terminal.clone(), Some((self.clone(), LogLevel::Info))) .ok(); Ok(()) diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index 81cd746d..293bc7b0 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -5,7 +5,8 @@ use core::ptr::NonNull; use abi::path::Path; use ext2::Ext2Fs; use libk::{ - block, devfs, + block, + fs::{devfs, sysfs}, vfs::{self, register_root, IoContext, NodeRef}, }; use libk_mm::{ @@ -21,7 +22,7 @@ use yggdrasil_abi::{error::Error, io::MountOptions}; pub use pseudo::add_pseudo_devices; pub mod pseudo; -pub mod sysfs; +// pub mod sysfs; /// Describes in-memory filesystem image used as initial root pub struct Initrd { diff --git a/kernel/src/fs/pseudo.rs b/kernel/src/fs/pseudo.rs index 7a06a8fd..cb28bfef 100644 --- a/kernel/src/fs/pseudo.rs +++ b/kernel/src/fs/pseudo.rs @@ -6,8 +6,8 @@ use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use device_api::device::Device; use libk::{ - devfs, device::char::CharDevice, + fs::devfs, random, vfs::{impls::read_fn_node, FileReadiness}, }; diff --git a/kernel/src/fs/sysfs.rs b/kernel/src/fs/sysfs.rs deleted file mode 100644 index e3dd4634..00000000 --- a/kernel/src/fs/sysfs.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! "System" filesystem implementation - -use core::sync::atomic::Ordering; - -use abi::error::Error; -use alloc::{format, string::String}; -use git_version::git_version; -use kernel_arch_interface::cpu::CpuFeatureSet; -use libk::{ - arch::Cpu, - debug, - task::{cpu_count, sched}, - vfs::{ - impls::{const_value_node, mdir, read_fn_node, ReadOnlyFnValueNode}, - NodeRef, - }, -}; -use libk_mm::phys; -use libk_util::OneTimeInit; - -use crate::util; - -static ROOT: OneTimeInit = OneTimeInit::new(); - -/// Returns the root of the filesystem -pub fn root() -> &'static NodeRef { - ROOT.get() -} - -fn read_kernel_log(pos: u64, buffer: &mut [u8]) -> Result { - Ok(debug::RING_LOGGER_SINK.read(pos as usize, buffer)) -} - -fn feature_list(features: Option<&C>) -> String { - let mut list = String::new(); - if let Some(features) = features { - let mut cnt = 0; - features.iter().for_each(|feature| { - if cnt != 0 { - list.push(' '); - } - list.push_str(feature); - cnt += 1; - }); - } - list -} - -fn sched_stats() -> String { - let mut res = String::new(); - for i in 0..cpu_count() { - let stats = sched::stats(i); - res.push_str(&format!( - "{} {} {} {}", - stats.idle.load(Ordering::Relaxed), - stats.user.load(Ordering::Relaxed), - stats.kernel.load(Ordering::Relaxed), - stats.total.load(Ordering::Relaxed) - )); - } - res -} - -/// Sets up the entries within the filesystem -pub fn init() { - let d_kernel = mdir([ - ("version", const_value_node(env!("CARGO_PKG_VERSION"))), - ("rev", const_value_node(git_version!())), - ("log", read_fn_node(read_kernel_log)), - ]); - let d_proc = mdir([( - "sched_stats", - ReadOnlyFnValueNode::new_node(|| Ok(sched_stats())), - )]); - let d_mem_phys = mdir([ - ( - "total_pages", - ReadOnlyFnValueNode::new_node(|| Ok(phys::stats().total_usable_pages)), - ), - ( - "free_pages", - ReadOnlyFnValueNode::new_node(|| Ok(phys::stats().free_pages)), - ), - ( - "allocated_pages", - ReadOnlyFnValueNode::new_node(|| Ok(phys::stats().allocated_pages)), - ), - ]); - let d_mem = mdir([("phys", d_mem_phys)]); - // TODO per-CPU entries - let d_cpu_features = mdir([ - ( - "enabled", - ReadOnlyFnValueNode::new_node(|| Ok(feature_list(Cpu::local().enabled_features()))), - ), - ( - "available", - ReadOnlyFnValueNode::new_node(|| Ok(feature_list(Cpu::local().available_features()))), - ), - ]); - let d_cpu = mdir([("features", d_cpu_features)]); - let root = mdir([ - ("kernel", d_kernel), - ("cpu", d_cpu), - ("mem", d_mem), - ("proc", d_proc), - ("arch", const_value_node(util::arch_str())), - ("machine", const_value_node(util::machine_name())), - ]); - - ROOT.init(root); -} diff --git a/kernel/src/init.rs b/kernel/src/init.rs index c84f9d8e..04107be3 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -2,8 +2,8 @@ use abi::error::Error; use libk::{ - devfs, device::display::console, + fs::devfs, random, task::{binary::LoadOptions, process::Process, runtime, thread::Thread}, vfs::{impls::fn_symlink, IoContext, NodeRef}, diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 7367981c..6d912228 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -20,7 +20,8 @@ exact_size_is_empty, maybe_uninit_uninit_array, never_type, - format_args_nl + format_args_nl, + associated_type_defaults )] #![allow( clippy::new_without_default, @@ -34,12 +35,21 @@ #![no_std] #![no_main] -use alloc::borrow::ToOwned; +use abi::error::Error; +use alloc::{borrow::ToOwned, string::String}; use arch::Platform; -use fs::sysfs; use git_version::git_version; use kernel_arch::{Architecture, ArchitectureImpl}; -use libk::{arch::Cpu, devfs}; +use libk::{ + arch::Cpu, + fs::{ + devfs, + sysfs::{ + self, + attribute::{StringAttribute, StringAttributeOps}, + }, + }, +}; use libk_util::sync::SpinFence; use crate::{arch::PLATFORM, task::spawn_kernel_closure}; @@ -47,6 +57,7 @@ use crate::{arch::PLATFORM, task::spawn_kernel_closure}; extern crate yggdrasil_abi as abi; extern crate alloc; +#[cfg(not(rust_analyzer))] extern crate compiler_builtins; #[macro_use] @@ -75,6 +86,32 @@ pub fn kernel_secondary_main() -> ! { } } +fn register_sysfs_attributes() { + struct Version; + struct Arch; + + impl StringAttributeOps for Version { + const NAME: &'static str = "version"; + + fn read(_state: &Self::Data) -> Result { + Ok(git_version!().into()) + } + } + + impl StringAttributeOps for Arch { + const NAME: &'static str = "arch"; + + fn read(_state: &Self::Data) -> Result { + Ok(util::arch_str().into()) + } + } + + let kernel = sysfs::kernel().unwrap(); + + kernel.add_attribute(StringAttribute::from(Version)).ok(); + kernel.add_attribute(StringAttribute::from(Arch)).ok(); +} + /// Common kernel main function. Must be called for BSP processor only. /// /// # Prerequisites @@ -103,7 +140,7 @@ pub fn kernel_main() -> ! { Cpu::init_ipi_queues(ArchitectureImpl::cpu_count()); // Setup the sysfs - sysfs::init(); + register_sysfs_attributes(); fs::add_pseudo_devices().unwrap(); // Wait until all APs initialize