mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-04-21 07:38:29 -04:00
Merge pull request #197 from arihant2math/sysfs
This commit is contained in:
@@ -51,6 +51,8 @@ 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 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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
mkdir /bin
|
||||
mkdir /dev
|
||||
mkdir /proc
|
||||
mkdir /sys
|
||||
mkdir /tmp
|
||||
symlink /bin/[ /bin/busybox
|
||||
symlink /bin/[[ /bin/busybox
|
||||
|
||||
177
src/drivers/fs/cgroup/mod.rs
Normal file
177
src/drivers/fs/cgroup/mod.rs
Normal file
@@ -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<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
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<Box<dyn DirStream>> {
|
||||
#[allow(unused_mut)]
|
||||
let mut entries: Vec<Dirent> = 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<RootInode>,
|
||||
}
|
||||
|
||||
impl CgroupFs {
|
||||
fn new() -> Arc<Self> {
|
||||
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<Arc<dyn Inode>> {
|
||||
Ok(self.root.clone())
|
||||
}
|
||||
|
||||
fn id(&self) -> u64 {
|
||||
CGROUPFS_ID
|
||||
}
|
||||
}
|
||||
|
||||
static SYSFS_INSTANCE: OnceLock<Arc<CgroupFs>> = 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<CgroupFs> {
|
||||
SYSFS_INSTANCE
|
||||
.get_or_init(|| {
|
||||
log::info!("cgroupfs 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<Self>) -> Option<Arc<dyn FilesystemDriver>> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FilesystemDriver for CgroupFsDriver {
|
||||
async fn construct(
|
||||
&self,
|
||||
_fs_id: u64,
|
||||
device: Option<Box<dyn BlockDevice>>,
|
||||
) -> Result<Arc<dyn Filesystem>> {
|
||||
if device.is_some() {
|
||||
warn!("cgroupfs should not be constructed with a block device");
|
||||
return Err(KernelError::InvalidValue);
|
||||
}
|
||||
Ok(cgroupfs())
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,20 @@
|
||||
use alloc::sync::Arc;
|
||||
use cgroup::CgroupFsDriver;
|
||||
use dev::DevFsDriver;
|
||||
use ext4::Ext4FsDriver;
|
||||
use fat32::Fat32FsDriver;
|
||||
use proc::ProcFsDriver;
|
||||
use sys::SysFsDriver;
|
||||
use tmpfs::TmpFsDriver;
|
||||
|
||||
use super::DM;
|
||||
|
||||
pub mod cgroup;
|
||||
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 +24,7 @@ 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()));
|
||||
dm.insert_driver(Arc::new(CgroupFsDriver::new()));
|
||||
}
|
||||
|
||||
226
src/drivers/fs/sys/mod.rs
Normal file
226
src/drivers/fs/sys/mod.rs
Normal file
@@ -0,0 +1,226 @@
|
||||
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<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
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<Box<dyn DirStream>> {
|
||||
#[allow(unused_mut)]
|
||||
let mut entries: Vec<Dirent> = 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! {
|
||||
CgroupInode,
|
||||
"fs/cgroup",
|
||||
}
|
||||
|
||||
static_dir! {
|
||||
FsInode,
|
||||
"fs",
|
||||
"cgroup" => FileType::Directory, CgroupInode,
|
||||
}
|
||||
|
||||
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<RootInode>,
|
||||
}
|
||||
|
||||
impl SysFs {
|
||||
fn new() -> Arc<Self> {
|
||||
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<Arc<dyn Inode>> {
|
||||
Ok(self.root.clone())
|
||||
}
|
||||
|
||||
fn id(&self) -> u64 {
|
||||
SYSFS_ID
|
||||
}
|
||||
}
|
||||
|
||||
static SYSFS_INSTANCE: OnceLock<Arc<SysFs>> = 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> {
|
||||
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<Self>) -> Option<Arc<dyn FilesystemDriver>> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FilesystemDriver for SysFsDriver {
|
||||
async fn construct(
|
||||
&self,
|
||||
_fs_id: u64,
|
||||
device: Option<Box<dyn BlockDevice>>,
|
||||
) -> Result<Arc<dyn Filesystem>> {
|
||||
if device.is_some() {
|
||||
warn!("sysfs should not be constructed with a block device");
|
||||
return Err(KernelError::InvalidValue);
|
||||
}
|
||||
Ok(sysfs())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user