fs: rework sysfs
This commit is contained in:
parent
047746d134
commit
cb5814a5ce
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -458,6 +458,7 @@ dependencies = [
|
|||||||
"device-api",
|
"device-api",
|
||||||
"discrete_range_map",
|
"discrete_range_map",
|
||||||
"fdt-rs",
|
"fdt-rs",
|
||||||
|
"libk",
|
||||||
"libk-mm",
|
"libk-mm",
|
||||||
"libk-util",
|
"libk-util",
|
||||||
"log",
|
"log",
|
||||||
|
@ -12,7 +12,7 @@ use device_api::{
|
|||||||
interrupt::{InterruptAffinity, InterruptHandler},
|
interrupt::{InterruptAffinity, InterruptHandler},
|
||||||
};
|
};
|
||||||
use error::AhciError;
|
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_mm::{address::AsPhysicalAddress, device::DeviceMemoryIo, PageBox};
|
||||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||||
use port::AhciPort;
|
use port::AhciPort;
|
||||||
|
@ -10,6 +10,7 @@ yggdrasil-abi.workspace = true
|
|||||||
device-api = { path = "../device-api", features = ["derive"] }
|
device-api = { path = "../device-api", features = ["derive"] }
|
||||||
libk-mm.workspace = true
|
libk-mm.workspace = true
|
||||||
libk-util.workspace = true
|
libk-util.workspace = true
|
||||||
|
libk.workspace = true
|
||||||
|
|
||||||
fdt-rs.workspace = true
|
fdt-rs.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
@ -70,6 +70,11 @@ impl<'a> DeviceTree<'a> {
|
|||||||
self.tree.totalsize()
|
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
|
/// Returns the root node of this device tree
|
||||||
pub fn root(&self) -> TNode {
|
pub fn root(&self) -> TNode {
|
||||||
self.index.root()
|
self.index.root()
|
||||||
@ -171,3 +176,5 @@ impl<'a> DeviceTree<'a> {
|
|||||||
DevTree::read_totalsize(header).map_err(|_| Error::InvalidArgument)
|
DevTree::read_totalsize(header).map_err(|_| Error::InvalidArgument)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for DeviceTree<'_> {}
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
//! Utility functions for device tree handling
|
//! Utility functions for device tree handling
|
||||||
use fdt_rs::index::iters::DevTreeIndexNodeSiblingIter;
|
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 libk_mm::{address::PhysicalAddress, phys::PhysicalMemoryRegion};
|
||||||
|
|
||||||
use crate::{node::DeviceTreeNodeExt, property::DeviceTreePropertyRead, tree::DeviceTree};
|
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<usize, Error> {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ use bytemuck::{Pod, Zeroable};
|
|||||||
|
|
||||||
use crate::RawTable;
|
use crate::RawTable;
|
||||||
|
|
||||||
pub const KERNEL_L3_COUNT: usize = 4;
|
pub const KERNEL_L3_COUNT: usize = 8;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -5,10 +5,15 @@
|
|||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
fmt::{self, Arguments},
|
fmt::{self, Arguments},
|
||||||
|
str::FromStr,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::{
|
||||||
|
format,
|
||||||
|
string::{String, ToString},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
use libk_util::{
|
use libk_util::{
|
||||||
ring::RingBuffer,
|
ring::RingBuffer,
|
||||||
sync::{
|
sync::{
|
||||||
@ -19,7 +24,14 @@ use libk_util::{
|
|||||||
};
|
};
|
||||||
use yggdrasil_abi::error::Error;
|
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 MAX_DEBUG_SINKS: usize = 8;
|
||||||
const RING_LOGGER_CAPACITY: usize = 65536;
|
const RING_LOGGER_CAPACITY: usize = 65536;
|
||||||
@ -116,6 +128,12 @@ impl DebugSinkWrapper {
|
|||||||
Self::Arc(level, _) => *level,
|
Self::Arc(level, _) => *level,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_level(&mut self, target: LogLevel) {
|
||||||
|
match self {
|
||||||
|
Self::Arc(level, _) => *level = target,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl log::Log for DebugSinkWrapper {
|
impl log::Log for DebugSinkWrapper {
|
||||||
@ -315,9 +333,51 @@ static DEBUG_SINKS: IrqSafeRwLock<StaticVector<DebugSinkWrapper, MAX_DEBUG_SINKS
|
|||||||
/// See [RingLoggerSink]
|
/// See [RingLoggerSink]
|
||||||
pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new();
|
pub static RING_LOGGER_SINK: RingLoggerSink = RingLoggerSink::new();
|
||||||
|
|
||||||
|
fn make_sysfs_sink_object(index: usize) -> Arc<KObject<usize>> {
|
||||||
|
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<String, Error> {
|
||||||
|
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
|
/// Adds a debugging output sink
|
||||||
pub fn add_sink(sink: Arc<dyn DebugSink>, level: LogLevel) {
|
pub fn add_sink(sink: Arc<dyn DebugSink>, 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<dyn DebugSink>, level: LogLevel) {
|
pub fn add_serial_sink(sink: Arc<dyn DebugSink>, level: LogLevel) {
|
||||||
@ -349,3 +409,34 @@ pub fn init() {
|
|||||||
.map(|_| log::set_max_level(log::LevelFilter::Trace))
|
.map(|_| log::set_max_level(log::LevelFilter::Trace))
|
||||||
.ok();
|
.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<Self, Self::Err> {
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ use yggdrasil_abi::error::Error;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
debug::{self, DebugSink, LogLevel},
|
debug::{self, DebugSink, LogLevel},
|
||||||
devfs,
|
fs::devfs,
|
||||||
vfs::NodeRef,
|
vfs::NodeRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
kernel/libk/src/fs/mod.rs
Normal file
2
kernel/libk/src/fs/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod devfs;
|
||||||
|
pub mod sysfs;
|
128
kernel/libk/src/fs/sysfs/attribute/bytes.rs
Normal file
128
kernel/libk/src/fs/sysfs/attribute/bytes.rs
Normal file
@ -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<usize, Error> {
|
||||||
|
let _ = state;
|
||||||
|
let _ = pos;
|
||||||
|
let _ = buffer;
|
||||||
|
Err(Error::NotImplemented)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(state: &Self::Data, pos: usize, buffer: &[u8]) -> Result<usize, Error> {
|
||||||
|
let _ = state;
|
||||||
|
let _ = pos;
|
||||||
|
let _ = buffer;
|
||||||
|
Err(Error::ReadOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(state: &Self::Data) -> usize {
|
||||||
|
let _ = state;
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BytesAttribute<V: BytesAttributeOps>(PhantomData<V>);
|
||||||
|
|
||||||
|
struct BytesAttributeNode<V: BytesAttributeOps> {
|
||||||
|
object: Arc<KObject<V::Data>>,
|
||||||
|
_pd: PhantomData<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: BytesAttributeOps> CommonImpl for BytesAttributeNode<V> {
|
||||||
|
fn size(&self, _node: &NodeRef) -> Result<u64, Error> {
|
||||||
|
Ok(V::size(&self.object.data) as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: BytesAttributeOps> RegularImpl for BytesAttributeNode<V> {
|
||||||
|
fn open(
|
||||||
|
&self,
|
||||||
|
_node: &NodeRef,
|
||||||
|
opts: OpenOptions,
|
||||||
|
) -> Result<(u64, Option<InstanceData>), 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<usize, Error> {
|
||||||
|
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<usize, Error> {
|
||||||
|
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<V: BytesAttributeOps> From<V> for BytesAttribute<V> {
|
||||||
|
fn from(_value: V) -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: BytesAttributeOps> Attribute<V::Data> for BytesAttribute<V> {
|
||||||
|
fn instantiate(&self, parent: &Arc<KObject<V::Data>>) -> Result<NodeRef, Error> {
|
||||||
|
let mode = match V::WRITEABLE {
|
||||||
|
false => FileMode::new(0o444),
|
||||||
|
true => FileMode::new(0o644),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Node::regular_kernel(
|
||||||
|
BytesAttributeNode {
|
||||||
|
object: parent.clone(),
|
||||||
|
_pd: PhantomData::<V>,
|
||||||
|
},
|
||||||
|
NodeFlags::IN_MEMORY_PROPS,
|
||||||
|
mode,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
V::NAME
|
||||||
|
}
|
||||||
|
}
|
17
kernel/libk/src/fs/sysfs/attribute/mod.rs
Normal file
17
kernel/libk/src/fs/sysfs/attribute/mod.rs
Normal file
@ -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<D>: Sync + Send {
|
||||||
|
fn instantiate(&self, parent: &Arc<KObject<D>>) -> Result<NodeRef, Error>;
|
||||||
|
fn name(&self) -> &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use bytes::{BytesAttribute, BytesAttributeOps};
|
||||||
|
pub use string::{StringAttribute, StringAttributeOps};
|
193
kernel/libk/src/fs/sysfs/attribute/string.rs
Normal file
193
kernel/libk/src/fs/sysfs/attribute/string.rs
Normal file
@ -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<String, Error> {
|
||||||
|
let _ = state;
|
||||||
|
Err(Error::NotImplemented)
|
||||||
|
}
|
||||||
|
fn write(state: &Self::Data, value: &str) -> Result<(), Error> {
|
||||||
|
let _ = state;
|
||||||
|
let _ = value;
|
||||||
|
Err(Error::ReadOnly)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StringAttribute<V: StringAttributeOps>(PhantomData<V>);
|
||||||
|
|
||||||
|
struct StringAttributeNode<V: StringAttributeOps> {
|
||||||
|
object: Arc<KObject<V::Data>>,
|
||||||
|
_pd: PhantomData<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StringAttributeState {
|
||||||
|
value: IrqSafeRwLock<Vec<u8>>,
|
||||||
|
modified: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: StringAttributeOps> CommonImpl for StringAttributeNode<V> {
|
||||||
|
fn size(&self, _node: &NodeRef) -> Result<u64, Error> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: StringAttributeOps> RegularImpl for StringAttributeNode<V> {
|
||||||
|
fn open(
|
||||||
|
&self,
|
||||||
|
_node: &NodeRef,
|
||||||
|
opts: OpenOptions,
|
||||||
|
) -> Result<(u64, Option<InstanceData>), 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::<StringAttributeState>()
|
||||||
|
.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<usize, Error> {
|
||||||
|
let instance = instance.ok_or(Error::InvalidFile)?;
|
||||||
|
let instance = instance
|
||||||
|
.downcast_ref::<StringAttributeState>()
|
||||||
|
.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<usize, Error> {
|
||||||
|
if !V::WRITEABLE {
|
||||||
|
return Err(Error::InvalidFile);
|
||||||
|
}
|
||||||
|
let instance = instance.ok_or(Error::InvalidFile)?;
|
||||||
|
let instance = instance
|
||||||
|
.downcast_ref::<StringAttributeState>()
|
||||||
|
.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<V: StringAttributeOps> From<V> for StringAttribute<V> {
|
||||||
|
fn from(_value: V) -> Self {
|
||||||
|
Self(PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: StringAttributeOps> Attribute<V::Data> for StringAttribute<V> {
|
||||||
|
fn instantiate(&self, parent: &Arc<KObject<V::Data>>) -> Result<Arc<Node>, Error> {
|
||||||
|
let mode = match V::WRITEABLE {
|
||||||
|
false => FileMode::new(0o444),
|
||||||
|
true => FileMode::new(0o644),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Node::regular_kernel(
|
||||||
|
StringAttributeNode {
|
||||||
|
object: parent.clone(),
|
||||||
|
_pd: PhantomData::<V>,
|
||||||
|
},
|
||||||
|
NodeFlags::IN_MEMORY_PROPS,
|
||||||
|
mode,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
V::NAME
|
||||||
|
}
|
||||||
|
}
|
30
kernel/libk/src/fs/sysfs/mod.rs
Normal file
30
kernel/libk/src/fs/sysfs/mod.rs
Normal file
@ -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<NodeRef> = OneTimeInit::new();
|
||||||
|
|
||||||
|
pub fn root() -> &'static NodeRef {
|
||||||
|
ROOT.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kernel() -> Option<&'static Arc<KObject<()>>> {
|
||||||
|
object::KERNEL_OBJECT.try_get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug() -> Option<&'static Arc<KObject<()>>> {
|
||||||
|
object::DEBUG_OBJECT.try_get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device() -> Option<&'static Arc<KObject<()>>> {
|
||||||
|
object::DEVICE_OBJECT.try_get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
ROOT.init(object::setup_fixed_objects());
|
||||||
|
}
|
69
kernel/libk/src/fs/sysfs/object.rs
Normal file
69
kernel/libk/src/fs/sysfs/object.rs
Normal file
@ -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<D> {
|
||||||
|
pub(super) data: D,
|
||||||
|
pub(super) node: Arc<Node>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> KObject<D> {
|
||||||
|
pub fn new(data: D) -> Arc<Self> {
|
||||||
|
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<A: Attribute<D>>(self: &Arc<Self>, attribute: A) -> Result<(), Error> {
|
||||||
|
let node = attribute.instantiate(self)?;
|
||||||
|
self.node.add_child(attribute.name(), node)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_object<S: Into<String>, T>(
|
||||||
|
&self,
|
||||||
|
name: S,
|
||||||
|
child: Arc<KObject<T>>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.node.add_child(name, child.node.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn data(&self) -> &D {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<D: Send> Send for KObject<D> {}
|
||||||
|
unsafe impl<D: Send> Sync for KObject<D> {}
|
||||||
|
|
||||||
|
// Static, fixed objects
|
||||||
|
// `/`
|
||||||
|
pub static ROOT_OBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||||
|
// `/kernel`
|
||||||
|
pub static KERNEL_OBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||||
|
// `/device`
|
||||||
|
pub static DEVICE_OBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||||
|
// `/debug`
|
||||||
|
pub static DEBUG_OBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
|
||||||
|
|
||||||
|
fn setup_fixed_object(root: &Arc<KObject<()>>, obj: &OneTimeInit<Arc<KObject<()>>>, name: &str) {
|
||||||
|
let obj = obj.init(KObject::new(()));
|
||||||
|
root.add_object(name, obj.clone()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_fixed_objects() -> Arc<Node> {
|
||||||
|
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()
|
||||||
|
}
|
@ -36,8 +36,8 @@ pub mod task;
|
|||||||
|
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
pub mod debug;
|
pub mod debug;
|
||||||
pub mod devfs;
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
|
pub mod fs;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod random;
|
pub mod random;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
@ -175,14 +175,30 @@ impl Node {
|
|||||||
(master, slave)
|
(master, slave)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new directory node with given [DirectoryImpl]
|
/// Creates a new directory node with given [DirectoryImpl] and permissions
|
||||||
pub fn directory<T: DirectoryImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
pub fn directory_kernel<T: DirectoryImpl + 'static>(
|
||||||
|
data: T,
|
||||||
|
flags: NodeFlags,
|
||||||
|
mode: FileMode,
|
||||||
|
) -> NodeRef {
|
||||||
let data = NodeImpl::Directory(DirectoryData {
|
let data = NodeImpl::Directory(DirectoryData {
|
||||||
imp: Box::new(data),
|
imp: Box::new(data),
|
||||||
mountpoint: IrqSafeSpinlock::new(None),
|
mountpoint: IrqSafeSpinlock::new(None),
|
||||||
children: IrqSafeSpinlock::new(Vec::new()),
|
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<T: DirectoryImpl + 'static>(data: T, flags: NodeFlags) -> NodeRef {
|
||||||
|
Self::directory_kernel(data, flags, FileMode::default_dir())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new file node with given [RegularImpl] and permissions
|
/// Creates a new file node with given [RegularImpl] and permissions
|
||||||
@ -196,11 +212,7 @@ impl Node {
|
|||||||
flags,
|
flags,
|
||||||
Metadata {
|
Metadata {
|
||||||
mode,
|
mode,
|
||||||
uid: UserId::root(),
|
..Metadata::default_file()
|
||||||
gid: GroupId::root(),
|
|
||||||
block_size: 0,
|
|
||||||
block_count: 0,
|
|
||||||
inode: None,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,10 @@ use kernel_arch_aarch64::{
|
|||||||
mem::{self, table::L3},
|
mem::{self, table::L3},
|
||||||
CPU_COUNT,
|
CPU_COUNT,
|
||||||
};
|
};
|
||||||
use libk::{devfs, task::runtime};
|
use libk::{
|
||||||
|
fs::{devfs, sysfs},
|
||||||
|
task::runtime,
|
||||||
|
};
|
||||||
use libk_mm::{
|
use libk_mm::{
|
||||||
address::{PhysicalAddress, Virtualize},
|
address::{PhysicalAddress, Virtualize},
|
||||||
phys,
|
phys,
|
||||||
@ -121,6 +124,7 @@ unsafe extern "C" fn __aarch64_bsp_upper_entry(dtb: PhysicalAddress) -> ! {
|
|||||||
|
|
||||||
exception::init_exceptions();
|
exception::init_exceptions();
|
||||||
|
|
||||||
|
sysfs::init();
|
||||||
devfs::init();
|
devfs::init();
|
||||||
|
|
||||||
runtime::init_task_queue();
|
runtime::init_task_queue();
|
||||||
|
@ -284,6 +284,9 @@ impl AArch64 {
|
|||||||
|
|
||||||
let dt = self.dt.get();
|
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);
|
let (machine_compatible, machine_name) = Self::machine_name(dt);
|
||||||
|
|
||||||
if let Some(compatible) = machine_compatible {
|
if let Some(compatible) = machine_compatible {
|
||||||
|
@ -158,7 +158,7 @@ impl Device for Pl011 {
|
|||||||
|
|
||||||
DEVICE_REGISTRY
|
DEVICE_REGISTRY
|
||||||
.serial_terminal
|
.serial_terminal
|
||||||
.register(terminal.clone(), Some((self.clone(), LogLevel::Debug)))
|
.register(terminal.clone(), Some((self.clone(), LogLevel::Info)))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -5,7 +5,8 @@ use core::ptr::NonNull;
|
|||||||
use abi::path::Path;
|
use abi::path::Path;
|
||||||
use ext2::Ext2Fs;
|
use ext2::Ext2Fs;
|
||||||
use libk::{
|
use libk::{
|
||||||
block, devfs,
|
block,
|
||||||
|
fs::{devfs, sysfs},
|
||||||
vfs::{self, register_root, IoContext, NodeRef},
|
vfs::{self, register_root, IoContext, NodeRef},
|
||||||
};
|
};
|
||||||
use libk_mm::{
|
use libk_mm::{
|
||||||
@ -21,7 +22,7 @@ use yggdrasil_abi::{error::Error, io::MountOptions};
|
|||||||
pub use pseudo::add_pseudo_devices;
|
pub use pseudo::add_pseudo_devices;
|
||||||
|
|
||||||
pub mod pseudo;
|
pub mod pseudo;
|
||||||
pub mod sysfs;
|
// pub mod sysfs;
|
||||||
|
|
||||||
/// Describes in-memory filesystem image used as initial root
|
/// Describes in-memory filesystem image used as initial root
|
||||||
pub struct Initrd {
|
pub struct Initrd {
|
||||||
|
@ -6,8 +6,8 @@ use alloc::{boxed::Box, sync::Arc};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use device_api::device::Device;
|
use device_api::device::Device;
|
||||||
use libk::{
|
use libk::{
|
||||||
devfs,
|
|
||||||
device::char::CharDevice,
|
device::char::CharDevice,
|
||||||
|
fs::devfs,
|
||||||
random,
|
random,
|
||||||
vfs::{impls::read_fn_node, FileReadiness},
|
vfs::{impls::read_fn_node, FileReadiness},
|
||||||
};
|
};
|
||||||
|
@ -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<NodeRef> = 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<usize, Error> {
|
|
||||||
Ok(debug::RING_LOGGER_SINK.read(pos as usize, buffer))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn feature_list<C: CpuFeatureSet>(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);
|
|
||||||
}
|
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use libk::{
|
use libk::{
|
||||||
devfs,
|
|
||||||
device::display::console,
|
device::display::console,
|
||||||
|
fs::devfs,
|
||||||
random,
|
random,
|
||||||
task::{binary::LoadOptions, process::Process, runtime, thread::Thread},
|
task::{binary::LoadOptions, process::Process, runtime, thread::Thread},
|
||||||
vfs::{impls::fn_symlink, IoContext, NodeRef},
|
vfs::{impls::fn_symlink, IoContext, NodeRef},
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
exact_size_is_empty,
|
exact_size_is_empty,
|
||||||
maybe_uninit_uninit_array,
|
maybe_uninit_uninit_array,
|
||||||
never_type,
|
never_type,
|
||||||
format_args_nl
|
format_args_nl,
|
||||||
|
associated_type_defaults
|
||||||
)]
|
)]
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::new_without_default,
|
clippy::new_without_default,
|
||||||
@ -34,12 +35,21 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use alloc::borrow::ToOwned;
|
use abi::error::Error;
|
||||||
|
use alloc::{borrow::ToOwned, string::String};
|
||||||
use arch::Platform;
|
use arch::Platform;
|
||||||
use fs::sysfs;
|
|
||||||
use git_version::git_version;
|
use git_version::git_version;
|
||||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
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 libk_util::sync::SpinFence;
|
||||||
|
|
||||||
use crate::{arch::PLATFORM, task::spawn_kernel_closure};
|
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 yggdrasil_abi as abi;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
#[cfg(not(rust_analyzer))]
|
||||||
extern crate compiler_builtins;
|
extern crate compiler_builtins;
|
||||||
|
|
||||||
#[macro_use]
|
#[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<String, Error> {
|
||||||
|
Ok(git_version!().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringAttributeOps for Arch {
|
||||||
|
const NAME: &'static str = "arch";
|
||||||
|
|
||||||
|
fn read(_state: &Self::Data) -> Result<String, Error> {
|
||||||
|
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.
|
/// Common kernel main function. Must be called for BSP processor only.
|
||||||
///
|
///
|
||||||
/// # Prerequisites
|
/// # Prerequisites
|
||||||
@ -103,7 +140,7 @@ pub fn kernel_main() -> ! {
|
|||||||
Cpu::init_ipi_queues(ArchitectureImpl::cpu_count());
|
Cpu::init_ipi_queues(ArchitectureImpl::cpu_count());
|
||||||
|
|
||||||
// Setup the sysfs
|
// Setup the sysfs
|
||||||
sysfs::init();
|
register_sysfs_attributes();
|
||||||
fs::add_pseudo_devices().unwrap();
|
fs::add_pseudo_devices().unwrap();
|
||||||
|
|
||||||
// Wait until all APs initialize
|
// Wait until all APs initialize
|
||||||
|
Loading…
x
Reference in New Issue
Block a user