Skip to content

Commit

Permalink
根据sysfs完善设备驱动模型 & 添加sysfs官方文档 (#254)
Browse files Browse the repository at this point in the history
* 根据sysfs完善设备驱动模型

* 添加sysfs官方文档
  • Loading branch information
TingSHub authored Apr 23, 2023
1 parent f678331 commit e0de0fd
Show file tree
Hide file tree
Showing 11 changed files with 581 additions and 150 deletions.
1 change: 1 addition & 0 deletions docs/kernel/filesystem/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ todo: 由于文件系统模块重构,文档暂时不可用,预计在2023年4

overview
vfs/index
sysfs

109 changes: 109 additions & 0 deletions docs/kernel/filesystem/sysfs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# SysFS

:::{note}
本文作者:黄厅

Email: <[email protected]>
:::

## 1. SysFS和设备驱动模型

### 1.1. 设备、驱动、总线等彼此之间关系错综复杂

&emsp;&emsp;如果想让内核运行流畅,那就必须为每个模块编码实现这些功能。如此一来,内核将变得非常臃肿、冗余。而设备模型的理念即是将这些代码抽象成各模块共用的框架,这样不但代码简洁了,也可让设备驱动开发者摆脱这本让人头痛但又必不可少的一劫,将有限的精力放于设备差异性的实现。

&emsp;&emsp;设备模型恰是提供了一个模板,一个被证明过的最优的思路和流程,这减少了开发者设计过程中不必要的错误,也给以后的维护扫除了障碍。

### 1.2. sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用。

&emsp;&emsp;sysfs可以看成与proc,devfs和devpty同类别的文件系统,该文件系统是虚拟的文件系统,可以更方便对系统设备进行管理。它可以产生一个包含所有系统硬件层次视图,与提供进程和状态信息的proc文件系统十分类似。sysfs把连接在系统上的设备和总线组织成为一个分级的文件,它们可以由用户空间存取,向用户空间导出内核的数据结构以及它们的属性。

## 2. DragosOS中的设备驱动模型

### 2.1 由设备和驱动构成基本元素

#### 2.1.1. 设备

```rust
/// @brief: 所有设备都应该实现该trait
pub trait Device: Any + Send + Sync + Debug {}
```

&emsp;&emsp;DragonOS采用全局设备管理器管理系统中所有的设备。

```rust
/// @brief Device管理器
#[derive(Debug, Clone)]
pub struct DeviceManager {
devices: BTreeMap<IdTable, Arc<dyn Device>>, // 所有设备
sys_info: Option<Arc<dyn IndexNode>>, // sys information
}
```

#### 2.1.2. 驱动

```rust
/// @brief: 所有驱动驱动都应该实现该trait
pub trait Driver: Any + Send + Sync + Debug {}
```

&emsp;&emsp;同样的,驱动也使用全局的驱动管理器来管理

```rust
/// @brief: 驱动管理器
#[derive(Debug, Clone)]
pub struct DriverManager {
drivers: BTreeMap<IdTable, Arc<dyn Driver>>, // 所有驱动
sys_info: Option<Arc<dyn IndexNode>>, // sys information
}
```

### 2.2. 总线

&emsp;&emsp;总线属于设备的一种类型,同样需要驱动来初始化,同时由于总线的特殊性,使用全局的总线管理器来进行管理。

```rust
/// @brief: 总线驱动trait,所有总线驱动都应实现该trait
pub trait BusDriver: Driver {}

/// @brief: 总线设备trait,所有总线都应实现该trait
pub trait Bus: Device {}

/// @brief: 总线管理结构体
#[derive(Debug, Clone)]
pub struct BusManager {
buses: BTreeMap<IdTable, Arc<dyn Bus>>, // 总线设备表
bus_drvs: BTreeMap<IdTable, Arc<dyn BusDriver>>, // 总线驱动表
sys_info: Option<Arc<dyn IndexNode>>, // 总线inode
}
```

&emsp;&emsp;可以看到,每个管理器中均存在sys_info,设备模型通过该成员与sysfs建立联系,sys_info指向sysfs中唯一的inode。对于device而言,对应sysfs下的devices文件夹,其他亦是如此。

## 3. 驱动开发如何进行

&emsp;&emsp;以平台总线platform为例,platform总线是一种虚拟总线,可以对挂载在其上的设备和驱动进行匹配,并驱动设备。该总线是一类设备,同时也是一类总线,编程时需要创建该设备实例,并为设备实例实现Device trait和Bus trait,以表明该结构是一类总线设备。同时,应该实现总线上的匹配规则,不同的总线匹配规则不同,该总线采用匹配表方式进行匹配,设备和驱动都应该存在一份匹配表,表示驱动支持的设备以及设备支持的驱动。

```rust
pub struct CompatibleTable(BTreeSet<&'static str>);
```

&emsp;&emsp;对于bus设备而言,需要调用bus_register,将bus注册进系统,并在sysfs中可视化。

```rust
/// @brief: 总线注册,将总线加入全局总线管理器中,并根据id table在sys/bus和sys/devices下生成文件夹
/// @parameter bus: Bus设备实体
/// @return: 成功:() 失败:DeviceError
pub fn bus_register<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
BUS_MANAGER.add_bus(bus.get_id_table(), bus.clone());
match sys_bus_register(&bus.get_id_table().to_name()) {
Ok(inode) => {
let _ = sys_bus_init(&inode);
return device_register(bus);
}
Err(_) => Err(DeviceError::RegisterError),
}
}
```

&emsp;&emsp;通过bus_register源码可知,该函数不仅在sysfs/bus下生成总线文件夹,同时内部调用device_register,该函数将总线加入设备管理器中,同时在sys/devices下生成设备文件夹。
107 changes: 72 additions & 35 deletions kernel/src/driver/base/device/bus.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
use super::{driver::Driver, Device, DeviceError, DeviceState, IdTable};
use super::{
device_register, device_unregister,
driver::{driver_register, driver_unregister, Driver, DriverError},
Device, DeviceError, DeviceState, IdTable,
};
use crate::{
filesystem::sysfs::{self, SYS_BUS_INODE},
kdebug,
filesystem::{
sysfs::{
bus::{sys_bus_init, sys_bus_register},
SYS_BUS_INODE,
},
vfs::IndexNode,
},
libs::spinlock::SpinLock,
};
use alloc::{collections::BTreeMap, sync::Arc};
use core::fmt::Debug;
use lazy_static::lazy_static;

lazy_static! {
pub static ref BUS_MANAGER: Arc<LockedBusManager> = Arc::new(LockedBusManager::new());
}

/// @brief: 总线状态
#[derive(Debug, Copy, Clone)]
pub enum BusState {
Expand Down Expand Up @@ -58,52 +71,31 @@ pub trait BusDriver: Driver {
}

/// @brief: 总线设备trait,所有总线都应实现该trait
pub trait Bus: Device {
/// @brief: 注册bus,在sysfs中生成相应文件夹
/// @parameter name: 文件夹名
/// @return: 注册成功,返回(),注册失败,返回错误码
fn register_bus(&self, name: &str) -> Result<(), DeviceError> {
match self.register_device(name) {
Ok(_) => {
let bus = sysfs::bus::bus_register(name).unwrap();
kdebug!(
"After register_bus: ls /sys/bus/: {:?}",
SYS_BUS_INODE().list()
);
match sysfs::bus::bus_init(&bus) {
Ok(_) => {
kdebug!("After register_bus: ls /sys/bus/{}: {:?}", name, bus.list());
return Ok(());
}
Err(_) => Err(DeviceError::RegisterError),
}
}
Err(err) => Err(err),
}
}
}
pub trait Bus: Device {}

/// @brief: 总线管理结构体
#[derive(Debug, Clone)]
pub struct BusManager {
buses: BTreeMap<IdTable, Arc<dyn Bus>>, // 总线设备表
bus_drvs: BTreeMap<IdTable, Arc<dyn BusDriver>>, // 总线驱动表
sys_info: Option<Arc<dyn IndexNode>>, // 总线inode
}

/// @brief: 总线管理结构体加锁
pub struct BusManagerLock(SpinLock<BusManager>);
/// @brief: bus管理(锁)
pub struct LockedBusManager(SpinLock<BusManager>);

/// @brief: 总线管理方法集
impl BusManagerLock {
impl LockedBusManager {
/// @brief: 创建总线管理实例
/// @parameter: None
/// @return: 总线管理实例
#[inline]
#[allow(dead_code)]
pub fn new() -> Self {
BusManagerLock(SpinLock::new(BusManager {
LockedBusManager(SpinLock::new(BusManager {
buses: BTreeMap::new(),
bus_drvs: BTreeMap::new(),
sys_info: Some(SYS_BUS_INODE()),
}))
}

Expand All @@ -124,7 +116,7 @@ impl BusManagerLock {
/// @return: None
#[inline]
#[allow(dead_code)]
pub fn add_bus_driver(&self, id_table: IdTable, bus_drv: Arc<dyn BusDriver>) {
pub fn add_driver(&self, id_table: IdTable, bus_drv: Arc<dyn BusDriver>) {
let mut bus_manager = self.0.lock();
bus_manager.bus_drvs.insert(id_table, bus_drv);
}
Expand Down Expand Up @@ -164,12 +156,57 @@ impl BusManagerLock {
/// @return: 总线驱动实例
#[inline]
#[allow(dead_code)]
pub fn get_bus_driver(&self, id_table: &IdTable) -> Option<Arc<dyn BusDriver>> {
pub fn get_driver(&self, id_table: &IdTable) -> Option<Arc<dyn BusDriver>> {
let bus_manager = self.0.lock();
return bus_manager.bus_drvs.get(id_table).cloned();
}

/// @brief: 获取总线管理器的sys information
/// @parameter None
/// @return: sys inode
#[inline]
#[allow(dead_code)]
fn sys_info(&self) -> Option<Arc<dyn IndexNode>> {
return self.0.lock().sys_info.clone();
}
}

lazy_static! {
pub static ref BUS_MANAGER: Arc<BusManagerLock> = Arc::new(BusManagerLock::new());
/// @brief: 总线注册,将总线加入全局总线管理器中,并根据id table在sys/bus和sys/devices下生成文件夹
/// @parameter bus: Bus设备实体
/// @return: 成功:() 失败:DeviceError
pub fn bus_register<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
BUS_MANAGER.add_bus(bus.get_id_table(), bus.clone());
match sys_bus_register(&bus.get_id_table().to_name()) {
Ok(inode) => {
let _ = sys_bus_init(&inode);
return device_register(bus);
}
Err(_) => Err(DeviceError::RegisterError),
}
}

/// @brief: 总线注销,将总线从全局总线管理器中删除,并在sys/bus和sys/devices下删除文件夹
/// @parameter bus: Bus设备实体
/// @return: 成功:() 失败:DeviceError
#[allow(dead_code)]
pub fn bus_unregister<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
BUS_MANAGER.add_bus(bus.get_id_table(), bus.clone());
return device_unregister(bus);
}

/// @brief: 总线驱动注册,将总线驱动加入全局总线管理器中
/// @parameter bus: Bus设备驱动实体
/// @return: 成功:() 失败:DeviceError
pub fn bus_driver_register<T: BusDriver>(bus_driver: Arc<T>) -> Result<(), DriverError> {
BUS_MANAGER.add_driver(bus_driver.get_id_table(), bus_driver.clone());
return driver_register(bus_driver);
}

/// @brief: 总线驱动注销,将总线从全局总线管理器中删除
/// @parameter bus: Bus设备驱动实体
/// @return: 成功:() 失败:DeviceError
#[allow(dead_code)]
pub fn bus_driver_unregister<T: BusDriver>(bus_driver: Arc<T>) -> Result<(), DriverError> {
BUS_MANAGER.add_driver(bus_driver.get_id_table(), bus_driver.clone());
return driver_unregister(bus_driver);
}
Loading

0 comments on commit e0de0fd

Please sign in to comment.