feature: simple sysfs

This commit is contained in:
Mark Poliakov 2021-12-09 09:02:28 +02:00
parent b4b99915ef
commit fcbe412732
9 changed files with 223 additions and 19 deletions

1
Cargo.lock generated
View File

@ -93,6 +93,7 @@ dependencies = [
"cfg-if",
"cortex-a",
"fdt-rs",
"fs-macros",
"kernel-macros",
"libsys",
"memfs",

View File

@ -92,10 +92,11 @@ initrd:
--target=../etc/$(ARCH)-osdev5.json \
-Z build-std=core,alloc,compiler_builtins \
$(CARGO_COMMON_OPTS)
mkdir -p $(O)/rootfs/bin $(O)/rootfs/sbin $(O)/rootfs/dev $(O)/rootfs/etc
mkdir -p $(O)/rootfs/bin $(O)/rootfs/sbin $(O)/rootfs/dev $(O)/rootfs/etc $(O)/rootfs/sys
cp etc/initrd/passwd $(O)/rootfs/etc
cp etc/initrd/shadow $(O)/rootfs/etc
touch $(O)/rootfs/dev/.do_no_remove
touch $(O)/rootfs/dev/.do_not_remove
touch $(O)/rootfs/sys/.do_not_remove
cp target/$(ARCH)-osdev5/$(PROFILE)/init $(O)/rootfs/init
cp target/$(ARCH)-osdev5/$(PROFILE)/shell $(O)/rootfs/bin
cp target/$(ARCH)-osdev5/$(PROFILE)/fuzzy $(O)/rootfs/bin

View File

@ -18,6 +18,7 @@ tock-registers = "0.7.x"
fdt-rs = { version = "0.x.x", default-features = false }
bitflags = "^1.3.0"
kernel-macros = { path = "macros" }
fs-macros = { path = "../fs/macros" }
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = { version = "6.x.x" }

View File

@ -10,7 +10,7 @@ use crate::dev::{
irq::IntSource,
Device,
};
use crate::fs::devfs;
use crate::fs::{devfs, sysfs};
use crate::dev::pseudo;
use libsys::error::Errno;
//use crate::debug::Level;
@ -97,6 +97,7 @@ extern "C" fn __aa64_bsp_main(fdt_base: usize) -> ! {
}
devfs::init();
sysfs::init();
machine::init_board().unwrap();

View File

@ -12,20 +12,39 @@
//! * [errorln!]
use crate::dev::serial::SerialDevice;
use libsys::debug::TraceLevel;
use libsys::{debug::TraceLevel, error::Errno};
use core::convert::TryFrom;
use core::fmt;
pub static LEVEL: Level = Level::Debug;
/// Kernel logging levels
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[repr(u32)]
pub enum Level {
/// Debugging information
Debug,
Debug = 1,
/// General informational messages
Info,
Info = 2,
/// Non-critical warnings
Warn,
Warn = 3,
/// Critical errors
Error,
Error = 4,
}
impl TryFrom<u32> for Level {
type Error = Errno;
#[inline(always)]
fn try_from(l: u32) -> Result<Level, Errno> {
match l {
1 => Ok(Level::Debug),
2 => Ok(Level::Info),
3 => Ok(Level::Warn),
4 => Ok(Level::Error),
_ => Err(Errno::InvalidArgument)
}
}
}
impl From<TraceLevel> for Level {
@ -114,13 +133,15 @@ macro_rules! errorln {
}
#[doc(hidden)]
pub fn _debug(_level: Level, args: fmt::Arguments) {
pub fn _debug(level: Level, args: fmt::Arguments) {
use crate::arch::machine;
use fmt::Write;
SerialOutput {
inner: machine::console(),
if level >= LEVEL {
SerialOutput {
inner: machine::console(),
}
.write_fmt(args)
.ok();
}
.write_fmt(args)
.ok();
}

View File

@ -8,6 +8,7 @@ use vfs::VnodeRef;
use memfs::BlockAllocator;
pub mod devfs;
pub mod sysfs;
/// Allocator implementation for memfs
#[derive(Clone, Copy)]
@ -32,9 +33,9 @@ unsafe impl BlockAllocator for MemfsBlockAlloc {
pub fn create_filesystem(options: &MountOptions) -> Result<VnodeRef, Errno> {
let fs_name = options.fs.unwrap();
if fs_name == "devfs" {
Ok(devfs::root().clone())
} else {
todo!();
match fs_name {
"devfs" => Ok(devfs::root().clone()),
"sysfs" => Ok(sysfs::root().clone()),
_ => todo!()
}
}

169
kernel/src/fs/sysfs.rs Normal file
View File

@ -0,0 +1,169 @@
use crate::util::InitOnce;
use alloc::boxed::Box;
use core::sync::atomic::{AtomicUsize, Ordering};
use fs_macros::auto_inode;
use libsys::{
error::Errno,
stat::{FileMode, OpenFlags, Stat},
};
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeImpl, VnodeKind, VnodeRef};
use core::fmt::{self, Write};
use core::str::FromStr;
use crate::debug::{self, Level};
struct NodeData<
R: Fn(&mut [u8]) -> Result<usize, Errno>,
W: Fn(&[u8]) -> Result<usize, Errno>,
> {
read_func: R,
write_func: W,
}
struct BufferWriter<'a> {
dst: &'a mut [u8],
pos: usize
}
impl<'a> fmt::Write for BufferWriter<'a> {
fn write_str(&mut self, s: &str) -> fmt::Result {
for byte in s.bytes() {
if self.pos == self.dst.len() {
todo!();
}
self.dst[self.pos] = byte;
self.pos += 1;
}
Ok(())
}
}
impl<'a> BufferWriter<'a> {
pub const fn new(dst: &'a mut [u8]) -> Self {
Self { dst, pos: 0 }
}
pub const fn count(&self) -> usize {
self.pos
}
}
#[auto_inode]
impl<
R: Fn(&mut [u8]) -> Result<usize, Errno>,
W: Fn(&[u8]) -> Result<usize, Errno>,
> VnodeImpl for NodeData<R, W>
{
fn open(&mut self, _node: VnodeRef, _mode: OpenFlags) -> Result<usize, Errno> {
Ok(0)
}
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
Ok(())
}
fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
if pos != 0 {
// TODO handle this
Ok(0)
} else {
(self.read_func)(data)
}
}
fn write(&mut self, _node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno> {
if pos != 0 {
todo!();
}
(self.write_func)(data)
}
}
impl<
R: Fn(&mut [u8]) -> Result<usize, Errno>,
W: Fn(&[u8]) -> Result<usize, Errno>,
> NodeData<R, W>
{
pub const fn new(read_func: R, write_func: W) -> Self {
Self {
read_func,
write_func,
}
}
}
static SYSFS_ROOT: InitOnce<VnodeRef> = InitOnce::new();
static TEST_COUNTER: AtomicUsize = AtomicUsize::new(0);
// TODO subdirs
fn add_generic_node<R, W>(parent: Option<VnodeRef>, name: &str, mode: FileMode, read: R, write: W)
where
R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static,
W: Fn(&[u8]) -> Result<usize, Errno> + 'static,
{
let node = Vnode::new(name, VnodeKind::Regular, Vnode::CACHE_STAT);
node.props_mut().mode = mode | FileMode::S_IFREG;
node.set_data(Box::new(NodeData::new(read, write)));
if let Some(parent) = parent {
parent.attach(node);
} else {
SYSFS_ROOT.get().attach(node);
}
}
pub fn add_read_write_node<R, W>(parent: Option<VnodeRef>, name: &str, read: R, write: W)
where
R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static,
W: Fn(&[u8]) -> Result<usize, Errno> + 'static,
{
add_generic_node(parent, name, FileMode::from_bits(0o600).unwrap(), read, write)
}
pub fn add_read_node<R>(parent: Option<VnodeRef>, name: &str, read: R) where R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static {
add_generic_node(parent, name, FileMode::from_bits(0o400).unwrap(), read, |_| Err(Errno::ReadOnly))
}
pub fn add_directory(parent: Option<VnodeRef>, name: &str) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
node.props_mut().mode = FileMode::from_bits(0o500).unwrap() | FileMode::S_IFDIR;
if let Some(parent) = parent {
parent.attach(node.clone());
} else {
SYSFS_ROOT.get().attach(node.clone());
}
Ok(node)
}
pub fn root() -> &'static VnodeRef {
SYSFS_ROOT.get()
}
pub fn init() {
let node = Vnode::new("", VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
node.props_mut().mode = FileMode::default_dir();
SYSFS_ROOT.init(node);
let debug_dir = add_directory(None, "debug").unwrap();
add_read_write_node(Some(debug_dir.clone()), "level", |buf| {
let mut writer = BufferWriter::new(buf);
write!(&mut writer, "{}\n", debug::LEVEL as u32).map_err(|_| Errno::InvalidArgument)?;
Ok(writer.count())
}, |buf| {
let s = core::str::from_utf8(buf).map_err(|_| Errno::InvalidArgument)?;
let value = u32::from_str(s).map_err(|_| Errno::InvalidArgument).and_then(Level::try_from)?;
todo!()
});
add_read_node(None, "uptime", |buf| {
use crate::arch::machine;
use crate::dev::timer::TimestampSource;
let mut writer = BufferWriter::new(buf);
let time = machine::local_timer().timestamp()?;
write!(&mut writer, "{} {}\n", time.as_secs(), time.subsec_nanos()).map_err(|_| Errno::InvalidArgument)?;
Ok(writer.count())
});
}

View File

@ -12,7 +12,8 @@
panic_info_message,
alloc_error_handler,
linked_list_cursors,
const_btree_new
const_btree_new,
const_generics_defaults,
)]
#![no_std]
#![no_main]

View File

@ -17,6 +17,14 @@ fn main() -> i32 {
},
)
.expect("Failed to mount devfs");
sys_mount(
"/sys",
&MountOptions {
device: None,
fs: Some("sysfs"),
},
)
.expect("Failed to mount sysfs");
if let Some(pid) = unsafe { sys_fork().unwrap() } {
let mut status = 0;