From c394e1823167c5055bc3688fdf83209905253f92 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Thu, 29 Jan 2026 15:07:22 -0800 Subject: [PATCH 1/3] tmp --- libkernel/src/fs/mod.rs | 1 + scripts/qemu-runner.sh | 2 +- scripts/symlinks.cmds | 1 + src/drivers/fs/mod.rs | 3 + src/drivers/fs/sys/mod.rs | 220 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 src/drivers/fs/sys/mod.rs diff --git a/libkernel/src/fs/mod.rs b/libkernel/src/fs/mod.rs index eb7294a..e50ddf9 100644 --- a/libkernel/src/fs/mod.rs +++ b/libkernel/src/fs/mod.rs @@ -51,6 +51,7 @@ bitflags::bitflags! { // Reserved psuedo filesystem instances created internally in the kernel. pub const DEVFS_ID: u64 = 1; pub const PROCFS_ID: u64 = 2; +pub const SYSFS_ID: u64 = 3; pub const FS_ID_START: u64 = 10; /// Trait for a mounted filesystem instance. Its main role is to act as a diff --git a/scripts/qemu-runner.sh b/scripts/qemu-runner.sh index 96a2ee5..eae48c5 100755 --- a/scripts/qemu-runner.sh +++ b/scripts/qemu-runner.sh @@ -23,4 +23,4 @@ bin="${elf%.elf}.bin" # Convert to binary format aarch64-none-elf-objcopy -O binary "$elf" "$bin" -qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" -append "$append_args --rootfs=ext4fs --automount=/dev,devfs --automount=/tmp,tmpfs --automount=/proc,procfs" +qemu-system-aarch64 -M virt,gic-version=3 -initrd moss.img -cpu cortex-a72 -m 2G -smp 4 -nographic -s -kernel "$bin" -append "$append_args --rootfs=ext4fs --automount=/dev,devfs --automount=/tmp,tmpfs --automount=/proc,procfs --automount=/sys,sysfs" diff --git a/scripts/symlinks.cmds b/scripts/symlinks.cmds index f836a23..6bf05ce 100644 --- a/scripts/symlinks.cmds +++ b/scripts/symlinks.cmds @@ -1,6 +1,7 @@ mkdir /bin mkdir /dev mkdir /proc +mkdir /sys mkdir /tmp symlink /bin/[ /bin/busybox symlink /bin/[[ /bin/busybox diff --git a/src/drivers/fs/mod.rs b/src/drivers/fs/mod.rs index 8939946..954c552 100644 --- a/src/drivers/fs/mod.rs +++ b/src/drivers/fs/mod.rs @@ -3,6 +3,7 @@ use dev::DevFsDriver; use ext4::Ext4FsDriver; use fat32::Fat32FsDriver; use proc::ProcFsDriver; +use sys::SysFsDriver; use tmpfs::TmpFsDriver; use super::DM; @@ -11,6 +12,7 @@ pub mod dev; pub mod ext4; pub mod fat32; pub mod proc; +pub mod sys; pub mod tmpfs; pub fn register_fs_drivers() { @@ -20,5 +22,6 @@ pub fn register_fs_drivers() { dm.insert_driver(Arc::new(Fat32FsDriver::new())); dm.insert_driver(Arc::new(DevFsDriver::new())); dm.insert_driver(Arc::new(ProcFsDriver::new())); + dm.insert_driver(Arc::new(SysFsDriver::new())); dm.insert_driver(Arc::new(TmpFsDriver::new())); } diff --git a/src/drivers/fs/sys/mod.rs b/src/drivers/fs/sys/mod.rs new file mode 100644 index 0000000..905a41c --- /dev/null +++ b/src/drivers/fs/sys/mod.rs @@ -0,0 +1,220 @@ +use crate::drivers::Driver; +use crate::fs::FilesystemDriver; +use crate::sync::OnceLock; +use alloc::boxed::Box; +use alloc::string::ToString; +use alloc::sync::Arc; +use alloc::vec::Vec; +use async_trait::async_trait; +use core::hash::Hasher; +use libkernel::error::FsError; +use libkernel::fs::attr::FileAttr; +use libkernel::fs::{ + BlockDevice, DirStream, Dirent, FileType, Inode, InodeId, SYSFS_ID, SimpleDirStream, +}; +use libkernel::{ + error::{KernelError, Result}, + fs::Filesystem, +}; +use log::warn; + +/// Deterministically generates an inode ID for the given path segments within the sysfs filesystem. +fn get_inode_id(path_segments: &[&str]) -> u64 { + let mut hasher = rustc_hash::FxHasher::default(); + // Ensure non-collision if other filesystems also use this method + hasher.write(b"sysfs"); + for segment in path_segments { + hasher.write(segment.as_bytes()); + } + let hash = hasher.finish(); + assert_ne!(hash, 0, "Generated inode ID cannot be zero"); + hash +} + +macro_rules! static_dir { + ($name:ident, $path:expr, $( $entry_name:expr => $entry_type:expr, $entry_ident:ident ),* $(,)? ) => { + struct $name { + id: InodeId, + attr: FileAttr, + } + + impl $name { + fn new(id: InodeId) -> Self { + Self { + id, + attr: FileAttr { + file_type: FileType::Directory, + ..FileAttr::default() + }, + } + } + + const fn num_entries() -> usize { + 0 $(+ { let _ = $entry_name; 1 })* + } + } + + #[async_trait] + impl Inode for $name { + fn id(&self) -> InodeId { + self.id + } + + async fn getattr(&self) -> Result { + Ok(self.attr.clone()) + } + + async fn lookup(&self, name: &str) -> Result> { + match name { + $( + $entry_name => { + let inode_id = InodeId::from_fsid_and_inodeid( + SYSFS_ID, + get_inode_id(&[$path, $entry_name]), + ); + Ok(Arc::new($entry_ident::new(inode_id))) + }, + )* + _ => Err(KernelError::Fs(FsError::NotFound)), + } + } + + async fn readdir(&self, start_offset: u64) -> Result> { + #[allow(unused_mut)] + let mut entries: Vec = Vec::with_capacity(Self::num_entries()); + $( + entries.push(Dirent { + id: InodeId::from_fsid_and_inodeid( + SYSFS_ID, + get_inode_id(&[$path, $entry_name]), + ), + name: $entry_name.to_string(), + offset: (entries.len() + 1) as u64, + file_type: $entry_type, + }); + )* + Ok(Box::new(SimpleDirStream::new(entries, start_offset))) + } + } + }; +} + +static_dir! { + DevBlockInode, + "dev/block", +} + +static_dir! { + DevCharInode, + "dev/char", +} + +static_dir! { + DevInode, + "dev", + "block" => FileType::Directory, DevBlockInode, + "char" => FileType::Directory, DevCharInode, +} + +static_dir! { + DevicesInode, + "devices", +} + +static_dir! { + FirmwareInode, + "firmware", +} + +static_dir! { + FsInode, + "fs", +} + +static_dir! { + KernelInode, + "kernel", +} + +static_dir! { + RootInode, + "", + "dev" => FileType::Directory, DevInode, + "devices" => FileType::Directory, DevicesInode, + "firmware" => FileType::Directory, FirmwareInode, + "fs" => FileType::Directory, FsInode, + "kernel" => FileType::Directory, KernelInode, +} + +pub struct SysFs { + root: Arc, +} + +impl SysFs { + fn new() -> Arc { + Arc::new(Self { + root: Arc::new(RootInode::new(InodeId::from_fsid_and_inodeid( + SYSFS_ID, + get_inode_id(&[]), + ))), + }) + } +} + +#[async_trait] +impl Filesystem for SysFs { + async fn root_inode(&self) -> Result> { + Ok(self.root.clone()) + } + + fn id(&self) -> u64 { + SYSFS_ID + } +} + +static SYSFS_INSTANCE: OnceLock> = OnceLock::new(); + +/// Initializes and/or returns the global singleton [`SysFs`] instance. +/// This is the main entry point for the rest of the kernel to interact with sysfs. +pub fn sysfs() -> Arc { + SYSFS_INSTANCE + .get_or_init(|| { + log::info!("sysfs initialized"); + SysFs::new() + }) + .clone() +} + +pub struct SysFsDriver; + +impl SysFsDriver { + #[must_use] + pub fn new() -> Self { + Self + } +} + +impl Driver for SysFsDriver { + fn name(&self) -> &'static str { + "sysfs" + } + + fn as_filesystem_driver(self: Arc) -> Option> { + Some(self) + } +} + +#[async_trait] +impl FilesystemDriver for SysFsDriver { + async fn construct( + &self, + _fs_id: u64, + device: Option>, + ) -> Result> { + if device.is_some() { + warn!("sysfs should not be constructed with a block device"); + return Err(KernelError::InvalidValue); + } + Ok(sysfs()) + } +} From 479926f767cec244076e9af8cce16b869b28685b Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sat, 7 Feb 2026 10:07:49 -0800 Subject: [PATCH 2/3] stub cgroup fs --- libkernel/src/fs/mod.rs | 1 + src/drivers/fs/cgroup/mod.rs | 177 +++++++++++++++++++++++++++++++++++ src/drivers/fs/mod.rs | 3 + src/drivers/fs/sys/mod.rs | 6 ++ 4 files changed, 187 insertions(+) create mode 100644 src/drivers/fs/cgroup/mod.rs diff --git a/libkernel/src/fs/mod.rs b/libkernel/src/fs/mod.rs index e50ddf9..a27c398 100644 --- a/libkernel/src/fs/mod.rs +++ b/libkernel/src/fs/mod.rs @@ -52,6 +52,7 @@ bitflags::bitflags! { pub const DEVFS_ID: u64 = 1; pub const PROCFS_ID: u64 = 2; pub const SYSFS_ID: u64 = 3; +pub const CGROUPFS_ID: u64 = 4; pub const FS_ID_START: u64 = 10; /// Trait for a mounted filesystem instance. Its main role is to act as a diff --git a/src/drivers/fs/cgroup/mod.rs b/src/drivers/fs/cgroup/mod.rs new file mode 100644 index 0000000..c0b4dd5 --- /dev/null +++ b/src/drivers/fs/cgroup/mod.rs @@ -0,0 +1,177 @@ +use crate::drivers::Driver; +use crate::fs::FilesystemDriver; +use crate::sync::OnceLock; +use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec::Vec; +use async_trait::async_trait; +use core::hash::Hasher; +use libkernel::error::FsError; +use libkernel::fs::attr::FileAttr; +use libkernel::fs::{ + BlockDevice, CGROUPFS_ID, DirStream, Dirent, FileType, Inode, InodeId, SimpleDirStream, +}; +use libkernel::{ + error::{KernelError, Result}, + fs::Filesystem, +}; +use log::warn; + +/// Deterministically generates an inode ID for the given path segments within the sysfs filesystem. +fn get_inode_id(path_segments: &[&str]) -> u64 { + let mut hasher = rustc_hash::FxHasher::default(); + // Ensure non-collision if other filesystems also use this method + hasher.write(b"cgroupfs"); + for segment in path_segments { + hasher.write(segment.as_bytes()); + } + let hash = hasher.finish(); + assert_ne!(hash, 0, "Generated inode ID cannot be zero"); + hash +} + +macro_rules! static_dir { + ($name:ident, $path:expr, $( $entry_name:expr => $entry_type:expr, $entry_ident:ident ),* $(,)? ) => { + struct $name { + id: InodeId, + attr: FileAttr, + } + + impl $name { + fn new(id: InodeId) -> Self { + Self { + id, + attr: FileAttr { + file_type: FileType::Directory, + ..FileAttr::default() + }, + } + } + + const fn num_entries() -> usize { + 0 $(+ { let _ = $entry_name; 1 })* + } + } + + #[async_trait] + impl Inode for $name { + fn id(&self) -> InodeId { + self.id + } + + async fn getattr(&self) -> Result { + Ok(self.attr.clone()) + } + + async fn lookup(&self, name: &str) -> Result> { + match name { + $( + $entry_name => { + let inode_id = InodeId::from_fsid_and_inodeid( + SYSFS_ID, + get_inode_id(&[$path, $entry_name]), + ); + Ok(Arc::new($entry_ident::new(inode_id))) + }, + )* + _ => Err(KernelError::Fs(FsError::NotFound)), + } + } + + async fn readdir(&self, start_offset: u64) -> Result> { + #[allow(unused_mut)] + let mut entries: Vec = Vec::with_capacity(Self::num_entries()); + $( + entries.push(Dirent { + id: InodeId::from_fsid_and_inodeid( + SYSFS_ID, + get_inode_id(&[$path, $entry_name]), + ), + name: $entry_name.to_string(), + offset: (entries.len() + 1) as u64, + file_type: $entry_type, + }); + )* + Ok(Box::new(SimpleDirStream::new(entries, start_offset))) + } + } + }; +} + +static_dir! { + RootInode, + "", +} + +pub struct CgroupFs { + root: Arc, +} + +impl CgroupFs { + fn new() -> Arc { + Arc::new(Self { + root: Arc::new(RootInode::new(InodeId::from_fsid_and_inodeid( + CGROUPFS_ID, + get_inode_id(&[]), + ))), + }) + } +} + +#[async_trait] +impl Filesystem for CgroupFs { + async fn root_inode(&self) -> Result> { + Ok(self.root.clone()) + } + + fn id(&self) -> u64 { + CGROUPFS_ID + } +} + +static SYSFS_INSTANCE: OnceLock> = OnceLock::new(); + +/// Initializes and/or returns the global singleton [`CgroupFs`] instance. +/// This is the main entry point for the rest of the kernel to interact with cgroupfs. +pub fn cgroupfs() -> Arc { + SYSFS_INSTANCE + .get_or_init(|| { + log::info!("sysfs initialized"); + CgroupFs::new() + }) + .clone() +} + +pub struct CgroupFsDriver; + +impl CgroupFsDriver { + #[must_use] + pub fn new() -> Self { + Self + } +} + +impl Driver for CgroupFsDriver { + fn name(&self) -> &'static str { + "cgroupfs" + } + + fn as_filesystem_driver(self: Arc) -> Option> { + Some(self) + } +} + +#[async_trait] +impl FilesystemDriver for CgroupFsDriver { + async fn construct( + &self, + _fs_id: u64, + device: Option>, + ) -> Result> { + if device.is_some() { + warn!("cgroupfs should not be constructed with a block device"); + return Err(KernelError::InvalidValue); + } + Ok(cgroupfs()) + } +} diff --git a/src/drivers/fs/mod.rs b/src/drivers/fs/mod.rs index 954c552..9de76fc 100644 --- a/src/drivers/fs/mod.rs +++ b/src/drivers/fs/mod.rs @@ -1,4 +1,5 @@ use alloc::sync::Arc; +use cgroup::CgroupFsDriver; use dev::DevFsDriver; use ext4::Ext4FsDriver; use fat32::Fat32FsDriver; @@ -8,6 +9,7 @@ use tmpfs::TmpFsDriver; use super::DM; +pub mod cgroup; pub mod dev; pub mod ext4; pub mod fat32; @@ -24,4 +26,5 @@ pub fn register_fs_drivers() { dm.insert_driver(Arc::new(ProcFsDriver::new())); dm.insert_driver(Arc::new(SysFsDriver::new())); dm.insert_driver(Arc::new(TmpFsDriver::new())); + dm.insert_driver(Arc::new(CgroupFsDriver::new())); } diff --git a/src/drivers/fs/sys/mod.rs b/src/drivers/fs/sys/mod.rs index 905a41c..178d3c3 100644 --- a/src/drivers/fs/sys/mod.rs +++ b/src/drivers/fs/sys/mod.rs @@ -126,9 +126,15 @@ static_dir! { "firmware", } +static_dir! { + CgroupInode, + "fs/cgroup", +} + static_dir! { FsInode, "fs", + "cgroup" => FileType::Directory, CgroupInode, } static_dir! { From 75afc15bc7cba6327dadefae474190973745cad0 Mon Sep 17 00:00:00 2001 From: Ashwin Naren Date: Sat, 7 Feb 2026 18:26:28 -0800 Subject: [PATCH 3/3] fix typo --- src/drivers/fs/cgroup/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/fs/cgroup/mod.rs b/src/drivers/fs/cgroup/mod.rs index c0b4dd5..772e627 100644 --- a/src/drivers/fs/cgroup/mod.rs +++ b/src/drivers/fs/cgroup/mod.rs @@ -136,7 +136,7 @@ static SYSFS_INSTANCE: OnceLock> = OnceLock::new(); pub fn cgroupfs() -> Arc { SYSFS_INSTANCE .get_or_init(|| { - log::info!("sysfs initialized"); + log::info!("cgroupfs initialized"); CgroupFs::new() }) .clone()