From 965ca90cce5d4939887598a745854fc8db333db7 Mon Sep 17 00:00:00 2001 From: huangshijia <1055114578@qq.com> Date: Tue, 2 Jun 2026 10:33:48 +0800 Subject: [PATCH 1/3] docs(driver_base): add design doc, security analysis, and rustdoc --- drivers/driver_base/docs/design.md | 112 +++++++++++++++++++ drivers/driver_base/docs/security.md | 83 ++++++++++++++ drivers/driver_base/src/lib.rs | 158 ++++++++++++++++++++++++--- 3 files changed, 337 insertions(+), 16 deletions(-) create mode 100644 drivers/driver_base/docs/design.md create mode 100644 drivers/driver_base/docs/security.md diff --git a/drivers/driver_base/docs/design.md b/drivers/driver_base/docs/design.md new file mode 100644 index 000000000..a2a0550f5 --- /dev/null +++ b/drivers/driver_base/docs/design.md @@ -0,0 +1,112 @@ +# driver_base — 设计文档 + +## 定位 + +本模块提供 x-kernel 所有设备驱动的公共基础接口,定义了设备分类枚举 +`DeviceKind`、驱动错误类型 `DriverError` / `DriverResult`,以及所有驱动 +必须实现的 `DriverOps` trait。它是 `drivers/` 下各子 crate +(block、net、display、input、vsock、virtio、kdriver)的共同依赖, +为内核驱动框架提供统一的类型契约。 + +## 背景 + +x-kernel 运行在裸机 `no_std` 环境中,无法使用 `std::io::Error` 等标准库 +错误类型。同时,内核需要对异构设备(块设备、网络设备、显示设备等)进行 +统一管理,因此需要一套轻量、无依赖的公共接口层,使各驱动 crate 在错误 +处理和设备身份描述上保持一致。 + +## 范围 + +涉及的源文件: + +``` +driver_base/ +├── src/ +│ └── lib.rs +│ +└── Cargo.toml +``` + +## 架构 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ driver_base │ +│ │ +│ DeviceKind ──分类──> DriverOps │ +│ │ │ │ +│ │ ├── name() │ +│ │ ├── device_kind() │ +│ │ └── irq() │ +│ │ │ +│ DriverError ──错误──> DriverResult │ +│ │ │ │ +│ ├── should_retry() │ +│ └── message() │ +└──────────────────────────────────────────────────────────────┘ + ▲ ▲ ▲ ▲ + │ │ │ │ + block crate net crate display crate virtio crate + (及 kdriver、input、vsock 等所有驱动子 crate) +``` + +| 组件 | 职责 | +|------|------| +| `DeviceKind` | 枚举所有支持的设备类别,提供 `as_str()` 稳定短名 | +| `DriverError` | 统一驱动错误码,提供重试判断和日志消息 | +| `DriverResult` | 驱动操作的专用 `Result` 类型别名 | +| `DriverOps` | 所有驱动必须实现的 trait,定义设备身份查询接口 | + +## 状态机 + +本模块为纯类型定义,无状态管理,不涉及状态机。 + +## 算法流程 + +本模块无复杂算法。核心逻辑仅为枚举匹配: + +### 错误重试判断 + +1. 调用者收到 `DriverResult::Err(e)` +2. 调用 `e.should_retry()` 判断是否为可重试错误(`WouldBlock` / `ResourceBusy`) +3. 若可重试,调用者按自身策略进行退避重试 + +### 设备分类查询 + +1. 通过 `DriverOps::device_kind()` 获取 `DeviceKind` +2. 按 `DeviceKind` 变体分发到对应子系统处理 + +## 并发模型 + +本模块仅定义类型和 trait,无内部可变状态,无并发问题。 + +- `DriverOps` 要求实现者满足 `Send + Sync`,确保 trait object 可跨线程共享。 +- `DeviceKind` 和 `DriverError` 均为 `Copy` 类型,天然线程安全。 + +## 设计决策 + +### 为什么用枚举而非字符串表示设备类别 + +使用 `#[repr(u8)]` 枚举而非字符串: +- 编译期穷举匹配,遗漏变体时编译器报错 +- 零堆分配,`Copy` 语义,适合热路径 +- `as_str()` 提供人类可读名称,仅在日志/调试时使用 + +### 为什么 DriverError 不实现 std::error::Error + +x-kernel 为 `no_std` 环境,无法依赖 `std::error::Error` trait。 +通过实现 `core::fmt::Display` 提供基本的错误描述能力。 + +### 为什么 DriverOps 只定义三个方法 + +`DriverOps` 故意保持最小接口: +- `name()` / `device_kind()` / `irq()` 是所有驱动都需要的身份信息 +- 具体操作(读写、配置等)由各子 crate 的专用 trait 定义 +- 避免在基础层引入不必要的抽象,保持正交性 + +### 为什么 irq() 返回 Option 而非 Result + +部分设备(如 ramdisk)不使用中断,`Option` 语义更准确: +- `None` 表示设备不使用中断(正常情况) +- `Some(irq)` 表示设备使用指定中断号 +- `Result` 的 `Err` 语义暗示操作失败,不适用于"无中断"的场景 diff --git a/drivers/driver_base/docs/security.md b/drivers/driver_base/docs/security.md new file mode 100644 index 000000000..b66f74e50 --- /dev/null +++ b/drivers/driver_base/docs/security.md @@ -0,0 +1,83 @@ +# driver_base — 安全与可靠性分析 + +## 信任模型 + +``` +驱动子 crate(block、net、display、input、vsock、virtio、kdriver) + │ + │ safe API: DeviceKind, DriverError, DriverResult, DriverOps + │ + v +┌──────────────────────────┐ +│ driver_base │ +│ │ +│ ┌── unsafe 边界 ──────┐ │ +│ │ (无 unsafe 代码) │ │ +│ └─────────────────────┘ │ +└──────────────────────────┘ +``` + +- **safe API 调用者**:模块仅提供纯 safe 类型定义和 trait,调用者无需额外证明安全性。 +- **unsafe API 调用者**:无 unsafe API。 + +## unsafe 代码清单 + +本模块不含任何 `unsafe` 块、`unsafe fn` 或 `unsafe impl`。 + +## 内存安全不变量 + +本模块无 `unsafe` 代码,无需维护额外的内存安全不变量。 +所有类型均为 `Copy` 或纯 trait 定义,不存在堆分配或裸指针操作。 + +## 线程安全 + +| 类型 | `Send` 条件 | `Sync` 条件 | +|------|-------------|-------------| +| `DeviceKind` | 自动 `Send`(`u8` 枚举,`Copy`) | 自动 `Sync`(`u8` 枚举,`Copy`) | +| `DriverError` | 自动 `Send`(`Copy` 枚举) | 自动 `Sync`(`Copy` 枚举) | +| `DriverResult` | 当 `T: Send` 时 `Send` | 当 `T: Sync` 时 `Sync` | +| `DriverOps` | trait 约束 `Send + Sync` | trait 约束 `Send + Sync` | + +## 威胁分析 + +| 编号 | 威胁描述 | 影响等级 | 触发条件 | 应对措施 | +|------|----------|----------|----------|----------| +| T-01 | `DriverOps` 实现者返回不一致的 `DeviceKind`,导致设备被错误子系统管理 | 中 | 驱动实现 bug,`device_kind()` 返回值与实际设备类型不符 | 各子 crate 在注册设备时校验 `DeviceKind` 与 trait 一致性;代码审查时重点检查 | +| T-02 | `DriverOps::name()` 返回空字符串或无效 UTF-8 引用 | 低 | 驱动实现 bug | `name()` 返回 `&str`,Rust 保证 UTF-8 合法性;空字符串不影响安全,仅影响日志可读性 | +| T-03 | `DriverError` 新增变体后调用方未穷举处理 | 低 | 修改 `DriverError` 枚举但未更新所有 `match` | `match` 穷举检查由编译器强制执行;`should_retry()` 和 `message()` 为集中处理点,新增变体时必须更新 | + +## 故障模式与影响分析(FMEA) + +| 编号 | 故障模式 | 故障原因 | 局部影响 | 系统影响 | 严重度 | 应对措施 | +|------|----------|----------|----------|----------|--------|----------| +| F-01 | `DriverOps` 实现返回错误的 `DeviceKind` | 驱动实现者误写 `device_kind()` 返回值 | 设备被路由到错误子系统 | 设备不可用,但不会导致内存安全问题 | 3 | 子系统注册时校验;代码审查 | +| F-02 | `irq()` 返回错误的中断号 | 驱动实现者误写中断号 | 中断路由到错误处理程序 | 可能导致设备中断丢失或错误处理 | 2 | 中断注册框架应校验 IRQ 号合法性 | +| F-03 | `should_retry()` 对新增错误变体返回 false | 新增 `DriverError` 变体后未更新 `should_retry()` | 可重试错误被当作永久失败 | 非阻塞操作提前失败 | 4 | 编译器穷举检查强制更新 `match` | +| F-04 | `message()` 对新增错误变体返回错误描述 | 新增 `DriverError` 变体后未更新 `message()` | 日志信息不准确 | 调试困难,无安全影响 | 4 | 编译器穷举检查强制更新 `match` | + +## 故障管理 + +- **错误码**:`DriverError` 枚举覆盖常见驱动故障场景,各变体语义明确。 +- **Panic 策略**:本模块无 panic 路径。 +- **故障恢复**:`should_retry()` 为调用者提供重试判断依据,具体恢复策略由调用者决定。 + +## 隐私分析 + +本模块不直接处理用户数据,不涉及隐私问题。 + +## 已知限制 + +1. `DriverError` 为固定枚举,无法携带附加上下文信息(如底层错误码、偏移量等), + 调用者如需详细错误信息需通过其他机制传递。 +2. `DriverOps::irq()` 返回 `Option`,不支持多个中断号的设备 + (如多队列网卡),后续可能需要扩展为返回中断号切片。 + +## 审计清单 + +修改本模块时需验证: + +- [ ] 每个 `unsafe` 块均有 `SAFETY:` 注释(当前无 unsafe 代码) +- [ ] 新增 `DeviceKind` 变体后所有 `match` 穷举已更新 +- [ ] 新增 `DriverError` 变体后 `should_retry()` 和 `message()` 已更新 +- [ ] `DriverOps` trait 变更为 breaking change,需同步所有实现者 +- [ ] 新增 panic 路径有对应的 PanicGuard 或等效保护(当前无 panic 路径) diff --git a/drivers/driver_base/src/lib.rs b/drivers/driver_base/src/lib.rs index 699c15fdd..37a2b8805 100644 --- a/drivers/driver_base/src/lib.rs +++ b/drivers/driver_base/src/lib.rs @@ -2,24 +2,61 @@ // Copyright 2025 KylinSoft Co., Ltd. // See LICENSES for license details. -//! Device driver interfaces used by x-kernel. It provides common traits and -//! types for implementing a device driver. +//! Device driver base interfaces for x-kernel. //! -//! You have to use this crate with the following crates for corresponding -//! device types: +//! This crate provides common traits and types for implementing a device driver. +//! It is the shared dependency of all driver sub-crates and defines the unified +//! type contract for device classification, error handling, and driver identity. //! -//! - [`kdriver_block`][2]: Common traits for block storage drivers. -//! - [`kdriver_display`][3]: Common traits and types for graphics display drivers. -//! - [`net`][4]: Common traits and types for network (NIC) drivers. +//! # Core types //! -//! [2]: ../kdriver_block/index.html -//! [3]: ../kdriver_display/index.html -//! [4]: ../net/index.html +//! - [`DeviceKind`] — enumeration of all supported device categories. +//! - [`DriverError`] / [`DriverResult`] — unified error type and `Result` alias. +//! - [`DriverOps`] — the minimal trait every device driver must implement. +//! +//! # Companion crates +//! +//! Use the following crates for device-type-specific traits: +//! +//! - `kdriver_block`: block storage drivers. +//! - `kdriver_display`: graphics display drivers. +//! - `net`: network (NIC) drivers. +//! +//! # Example +//! +//! ``` +//! use driver_base::{DeviceKind, DriverOps, DriverError, DriverResult}; +//! +//! struct MyDevice; +//! +//! impl DriverOps for MyDevice { +//! fn name(&self) -> &str { "my-device" } +//! fn device_kind(&self) -> DeviceKind { DeviceKind::Char } +//! } +//! +//! let dev = MyDevice; +//! assert_eq!(dev.name(), "my-device"); +//! assert_eq!(dev.device_kind(), DeviceKind::Char); +//! assert_eq!(dev.irq(), None); +//! ``` #![no_std] #![allow(rustdoc::broken_intra_doc_links)] /// All supported device kinds. +/// +/// Each variant corresponds to a device category in x-kernel. The `#[repr(u8)]` +/// layout ensures a compact, `Copy`-friendly representation suitable for hot +/// paths and FFI boundaries. +/// +/// # Example +/// +/// ``` +/// use driver_base::DeviceKind; +/// +/// let kind = DeviceKind::Net; +/// assert_eq!(kind.as_str(), "net"); +/// ``` #[repr(u8)] #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum DeviceKind { @@ -29,7 +66,7 @@ pub enum DeviceKind { Char, /// Network device (e.g., ethernet card). Net, - /// Graphic display device (e.g., GPU) + /// Graphic display device (e.g., GPU). Display, /// Input device (e.g., keyboard, mouse). Input, @@ -42,7 +79,23 @@ pub enum DeviceKind { } impl DeviceKind { - /// Stable short name for the device category. + /// Returns a stable short name for the device category. + /// + /// The returned string is suitable for logging and display purposes. + /// It remains stable across crate versions. + /// + /// # Returns + /// + /// A `&'static str` identifying the category (e.g., `"block"`, `"net"`). + /// + /// # Example + /// + /// ``` + /// use driver_base::DeviceKind; + /// + /// assert_eq!(DeviceKind::Block.as_str(), "block"); + /// assert_eq!(DeviceKind::Virtio9p.as_str(), "virtio-9p"); + /// ``` pub const fn as_str(self) -> &'static str { use DeviceKind::*; @@ -60,6 +113,20 @@ impl DeviceKind { } /// The error type for driver operation failures. +/// +/// Covers common failure modes shared across all driver sub-crates. Each variant +/// maps to a distinct category; callers use [`should_retry`](DriverError::should_retry) +/// to decide whether to re-attempt the operation. +/// +/// # Example +/// +/// ``` +/// use driver_base::DriverError; +/// +/// let err = DriverError::WouldBlock; +/// assert!(err.should_retry()); +/// assert_eq!(err.message(), "Try again"); +/// ``` #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum DriverError { /// An entity already exists. @@ -81,12 +148,45 @@ pub enum DriverError { } impl DriverError { - /// Whether the caller may retry the operation later. + /// Returns whether the caller may retry the operation later. + /// + /// Only [`WouldBlock`](DriverError::WouldBlock) and + /// [`ResourceBusy`](DriverError::ResourceBusy) are considered retryable. + /// All other variants indicate permanent failures for the current request. + /// + /// # Returns + /// + /// `true` if the error is transient and the operation may succeed on retry. + /// + /// # Example + /// + /// ``` + /// use driver_base::DriverError; + /// + /// assert!(DriverError::WouldBlock.should_retry()); + /// assert!(DriverError::ResourceBusy.should_retry()); + /// assert!(!DriverError::Io.should_retry()); + /// ``` pub const fn should_retry(self) -> bool { matches!(self, Self::WouldBlock | Self::ResourceBusy) } - /// Stable error message for display/logging. + /// Returns a stable human-readable message for the error. + /// + /// Suitable for logging and diagnostics. The message is guaranteed to + /// remain stable across crate versions. + /// + /// # Returns + /// + /// A `&'static str` describing the error. + /// + /// # Example + /// + /// ``` + /// use driver_base::DriverError; + /// + /// assert_eq!(DriverError::NoMemory.message(), "Not enough memory"); + /// ``` pub const fn message(self) -> &'static str { use DriverError::*; @@ -110,6 +210,21 @@ impl core::fmt::Display for DriverError { } /// A specialized `Result` type for device operations. +/// +/// This alias eliminates the need to write `Result` throughout +/// the driver subsystem. The default success type is `()`. +/// +/// # Example +/// +/// ``` +/// use driver_base::{DriverError, DriverResult}; +/// +/// fn try_read() -> DriverResult> { +/// Err(DriverError::WouldBlock) +/// } +/// +/// assert!(try_read().is_err()); +/// ``` pub type DriverResult = core::result::Result; /// Common metadata that every device implementation must expose. @@ -123,10 +238,21 @@ pub trait Device: Send + Sync { /// The name of the device. fn name(&self) -> &str; - /// The kind of the device. + /// Returns the kind (category) of the device. + /// + /// Used by the driver framework to route the device to the appropriate + /// subsystem for management. fn device_kind(&self) -> DeviceKind; - /// The IRQ number of the device, if applicable. + /// Returns the IRQ number of the device, if applicable. + /// + /// Devices that do not use interrupts (e.g., ramdisk) should return + /// `None`, which is the default. + /// + /// # Returns + /// + /// - `Some(irq)` if the device uses an interrupt. + /// - `None` if the device is interrupt-free (default). fn irq(&self) -> Option { None } -- Gitee From d72724ef4704fbb24d5fc74301d243e5acffa413 Mon Sep 17 00:00:00 2001 From: huangshijia <1055114578@qq.com> Date: Tue, 2 Jun 2026 10:34:55 +0800 Subject: [PATCH 2/3] fmt --- drivers/driver_base/src/lib.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/driver_base/src/lib.rs b/drivers/driver_base/src/lib.rs index 37a2b8805..7e1cc7e03 100644 --- a/drivers/driver_base/src/lib.rs +++ b/drivers/driver_base/src/lib.rs @@ -25,13 +25,18 @@ //! # Example //! //! ``` -//! use driver_base::{DeviceKind, DriverOps, DriverError, DriverResult}; +//! use driver_base::{DeviceKind, DriverError, DriverOps, DriverResult}; //! //! struct MyDevice; //! //! impl DriverOps for MyDevice { -//! fn name(&self) -> &str { "my-device" } -//! fn device_kind(&self) -> DeviceKind { DeviceKind::Char } +//! fn name(&self) -> &str { +//! "my-device" +//! } +//! +//! fn device_kind(&self) -> DeviceKind { +//! DeviceKind::Char +//! } //! } //! //! let dev = MyDevice; -- Gitee From 22a67af50fc163285766bf8e2ddd16d26e2d383b Mon Sep 17 00:00:00 2001 From: huangshijia <1055114578@qq.com> Date: Tue, 2 Jun 2026 18:04:28 +0800 Subject: [PATCH 3/3] fix rebase --- drivers/driver_base/docs/design.md | 29 +++++++++++------- drivers/driver_base/docs/security.md | 14 ++++----- drivers/driver_base/src/lib.rs | 46 +++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/drivers/driver_base/docs/design.md b/drivers/driver_base/docs/design.md index a2a0550f5..593505907 100644 --- a/drivers/driver_base/docs/design.md +++ b/drivers/driver_base/docs/design.md @@ -3,8 +3,8 @@ ## 定位 本模块提供 x-kernel 所有设备驱动的公共基础接口,定义了设备分类枚举 -`DeviceKind`、驱动错误类型 `DriverError` / `DriverResult`,以及所有驱动 -必须实现的 `DriverOps` trait。它是 `drivers/` 下各子 crate +`DeviceKind`、驱动错误类型 `DriverError` / `DriverResult`,以及所有设备 +必须实现的 `Device` trait。它是 `drivers/` 下各子 crate (block、net、display、input、vsock、virtio、kdriver)的共同依赖, 为内核驱动框架提供统一的类型契约。 @@ -33,7 +33,7 @@ driver_base/ ┌──────────────────────────────────────────────────────────────┐ │ driver_base │ │ │ -│ DeviceKind ──分类──> DriverOps │ +│ DeviceKind ──分类──> Device │ │ │ │ │ │ │ ├── name() │ │ │ ├── device_kind() │ @@ -52,10 +52,10 @@ driver_base/ | 组件 | 职责 | |------|------| -| `DeviceKind` | 枚举所有支持的设备类别,提供 `as_str()` 稳定短名 | +| `DeviceKind` | 枚举所有支持的设备类别(9 种),提供 `as_str()` 稳定短名 | | `DriverError` | 统一驱动错误码,提供重试判断和日志消息 | | `DriverResult` | 驱动操作的专用 `Result` 类型别名 | -| `DriverOps` | 所有驱动必须实现的 trait,定义设备身份查询接口 | +| `Device` | 所有设备必须实现的 trait,定义设备身份元数据接口 | ## 状态机 @@ -73,14 +73,14 @@ driver_base/ ### 设备分类查询 -1. 通过 `DriverOps::device_kind()` 获取 `DeviceKind` +1. 通过 `Device::device_kind()` 获取 `DeviceKind` 2. 按 `DeviceKind` 变体分发到对应子系统处理 ## 并发模型 本模块仅定义类型和 trait,无内部可变状态,无并发问题。 -- `DriverOps` 要求实现者满足 `Send + Sync`,确保 trait object 可跨线程共享。 +- `Device` 要求实现者满足 `Send + Sync`,确保 trait object 可跨线程共享。 - `DeviceKind` 和 `DriverError` 均为 `Copy` 类型,天然线程安全。 ## 设计决策 @@ -97,11 +97,11 @@ driver_base/ x-kernel 为 `no_std` 环境,无法依赖 `std::error::Error` trait。 通过实现 `core::fmt::Display` 提供基本的错误描述能力。 -### 为什么 DriverOps 只定义三个方法 +### 为什么 Device trait 只定义三个方法 -`DriverOps` 故意保持最小接口: -- `name()` / `device_kind()` / `irq()` 是所有驱动都需要的身份信息 -- 具体操作(读写、配置等)由各子 crate 的专用 trait 定义 +`Device` 故意保持最小接口,仅描述设备身份元数据: +- `name()` / `device_kind()` / `irq()` 是所有设备都需要的身份信息 +- 具体操作(读写、配置等)由各子 crate 的专用 trait 定义,以 `Device` 为 super-trait - 避免在基础层引入不必要的抽象,保持正交性 ### 为什么 irq() 返回 Option 而非 Result @@ -110,3 +110,10 @@ x-kernel 为 `no_std` 环境,无法依赖 `std::error::Error` trait。 - `None` 表示设备不使用中断(正常情况) - `Some(irq)` 表示设备使用指定中断号 - `Result` 的 `Err` 语义暗示操作失败,不适用于"无中断"的场景 + +### 为什么 DeviceKind 包含 Bus 变体 + +总线控制器(如 PCI 主桥)本身也是需要被驱动框架管理的设备: +- 总线驱动负责枚举和配置子设备 +- 统一纳入 `DeviceKind` 可复用设备注册和发现机制 +- 与其他设备类别享有相同的身份查询接口 diff --git a/drivers/driver_base/docs/security.md b/drivers/driver_base/docs/security.md index b66f74e50..2280da0ff 100644 --- a/drivers/driver_base/docs/security.md +++ b/drivers/driver_base/docs/security.md @@ -5,7 +5,7 @@ ``` 驱动子 crate(block、net、display、input、vsock、virtio、kdriver) │ - │ safe API: DeviceKind, DriverError, DriverResult, DriverOps + │ safe API: DeviceKind, DriverError, DriverResult, Device │ v ┌──────────────────────────┐ @@ -36,21 +36,21 @@ | `DeviceKind` | 自动 `Send`(`u8` 枚举,`Copy`) | 自动 `Sync`(`u8` 枚举,`Copy`) | | `DriverError` | 自动 `Send`(`Copy` 枚举) | 自动 `Sync`(`Copy` 枚举) | | `DriverResult` | 当 `T: Send` 时 `Send` | 当 `T: Sync` 时 `Sync` | -| `DriverOps` | trait 约束 `Send + Sync` | trait 约束 `Send + Sync` | +| `Device` | trait 约束 `Send + Sync` | trait 约束 `Send + Sync` | ## 威胁分析 | 编号 | 威胁描述 | 影响等级 | 触发条件 | 应对措施 | |------|----------|----------|----------|----------| -| T-01 | `DriverOps` 实现者返回不一致的 `DeviceKind`,导致设备被错误子系统管理 | 中 | 驱动实现 bug,`device_kind()` 返回值与实际设备类型不符 | 各子 crate 在注册设备时校验 `DeviceKind` 与 trait 一致性;代码审查时重点检查 | -| T-02 | `DriverOps::name()` 返回空字符串或无效 UTF-8 引用 | 低 | 驱动实现 bug | `name()` 返回 `&str`,Rust 保证 UTF-8 合法性;空字符串不影响安全,仅影响日志可读性 | +| T-01 | `Device` 实现者返回不一致的 `DeviceKind`,导致设备被错误子系统管理 | 中 | 驱动实现 bug,`device_kind()` 返回值与实际设备类型不符 | 各子 crate 在注册设备时校验 `DeviceKind` 与 trait 一致性;代码审查时重点检查 | +| T-02 | `Device::name()` 返回空字符串或无效 UTF-8 引用 | 低 | 驱动实现 bug | `name()` 返回 `&str`,Rust 保证 UTF-8 合法性;空字符串不影响安全,仅影响日志可读性 | | T-03 | `DriverError` 新增变体后调用方未穷举处理 | 低 | 修改 `DriverError` 枚举但未更新所有 `match` | `match` 穷举检查由编译器强制执行;`should_retry()` 和 `message()` 为集中处理点,新增变体时必须更新 | ## 故障模式与影响分析(FMEA) | 编号 | 故障模式 | 故障原因 | 局部影响 | 系统影响 | 严重度 | 应对措施 | |------|----------|----------|----------|----------|--------|----------| -| F-01 | `DriverOps` 实现返回错误的 `DeviceKind` | 驱动实现者误写 `device_kind()` 返回值 | 设备被路由到错误子系统 | 设备不可用,但不会导致内存安全问题 | 3 | 子系统注册时校验;代码审查 | +| F-01 | `Device` 实现返回错误的 `DeviceKind` | 驱动实现者误写 `device_kind()` 返回值 | 设备被路由到错误子系统 | 设备不可用,但不会导致内存安全问题 | 3 | 子系统注册时校验;代码审查 | | F-02 | `irq()` 返回错误的中断号 | 驱动实现者误写中断号 | 中断路由到错误处理程序 | 可能导致设备中断丢失或错误处理 | 2 | 中断注册框架应校验 IRQ 号合法性 | | F-03 | `should_retry()` 对新增错误变体返回 false | 新增 `DriverError` 变体后未更新 `should_retry()` | 可重试错误被当作永久失败 | 非阻塞操作提前失败 | 4 | 编译器穷举检查强制更新 `match` | | F-04 | `message()` 对新增错误变体返回错误描述 | 新增 `DriverError` 变体后未更新 `message()` | 日志信息不准确 | 调试困难,无安全影响 | 4 | 编译器穷举检查强制更新 `match` | @@ -69,7 +69,7 @@ 1. `DriverError` 为固定枚举,无法携带附加上下文信息(如底层错误码、偏移量等), 调用者如需详细错误信息需通过其他机制传递。 -2. `DriverOps::irq()` 返回 `Option`,不支持多个中断号的设备 +2. `Device::irq()` 返回 `Option`,不支持多个中断号的设备 (如多队列网卡),后续可能需要扩展为返回中断号切片。 ## 审计清单 @@ -79,5 +79,5 @@ - [ ] 每个 `unsafe` 块均有 `SAFETY:` 注释(当前无 unsafe 代码) - [ ] 新增 `DeviceKind` 变体后所有 `match` 穷举已更新 - [ ] 新增 `DriverError` 变体后 `should_retry()` 和 `message()` 已更新 -- [ ] `DriverOps` trait 变更为 breaking change,需同步所有实现者 +- [ ] `Device` trait 变更为 breaking change,需同步所有实现者 - [ ] 新增 panic 路径有对应的 PanicGuard 或等效保护(当前无 panic 路径) diff --git a/drivers/driver_base/src/lib.rs b/drivers/driver_base/src/lib.rs index 7e1cc7e03..9b01484d2 100644 --- a/drivers/driver_base/src/lib.rs +++ b/drivers/driver_base/src/lib.rs @@ -6,13 +6,13 @@ //! //! This crate provides common traits and types for implementing a device driver. //! It is the shared dependency of all driver sub-crates and defines the unified -//! type contract for device classification, error handling, and driver identity. +//! type contract for device classification, error handling, and device identity. //! //! # Core types //! //! - [`DeviceKind`] — enumeration of all supported device categories. //! - [`DriverError`] / [`DriverResult`] — unified error type and `Result` alias. -//! - [`DriverOps`] — the minimal trait every device driver must implement. +//! - [`Device`] — the minimal trait every device implementation must expose. //! //! # Companion crates //! @@ -25,11 +25,11 @@ //! # Example //! //! ``` -//! use driver_base::{DeviceKind, DriverError, DriverOps, DriverResult}; +//! use driver_base::{Device, DeviceKind, DriverError, DriverResult}; //! //! struct MyDevice; //! -//! impl DriverOps for MyDevice { +//! impl Device for MyDevice { //! fn name(&self) -> &str { //! "my-device" //! } @@ -99,7 +99,8 @@ impl DeviceKind { /// use driver_base::DeviceKind; /// /// assert_eq!(DeviceKind::Block.as_str(), "block"); - /// assert_eq!(DeviceKind::Virtio9p.as_str(), "virtio-9p"); + /// assert_eq!(DeviceKind::Fs9p.as_str(), "fs9p"); + /// assert_eq!(DeviceKind::Bus.as_str(), "bus"); /// ``` pub const fn as_str(self) -> &'static str { use DeviceKind::*; @@ -239,8 +240,43 @@ pub type DriverResult = core::result::Result; /// (block read/write, net send/recv, ...) live in the per-category /// sub-traits in their respective crates (`block::BlockDevice`, /// `net::NetDevice`, etc.) and require this trait as a super-trait. +/// +/// # Requirements +/// +/// Implementors must be `Send + Sync` so that trait objects can be shared +/// across threads. +/// +/// # Example +/// +/// ``` +/// use driver_base::{Device, DeviceKind}; +/// +/// struct SerialPort; +/// +/// impl Device for SerialPort { +/// fn name(&self) -> &str { +/// "serial0" +/// } +/// +/// fn device_kind(&self) -> DeviceKind { +/// DeviceKind::Char +/// } +/// +/// fn irq(&self) -> Option { +/// Some(4) +/// } +/// } +/// +/// let dev = SerialPort; +/// assert_eq!(dev.name(), "serial0"); +/// assert_eq!(dev.device_kind().as_str(), "char"); +/// assert_eq!(dev.irq(), Some(4)); +/// ``` pub trait Device: Send + Sync { /// The name of the device. + /// + /// The name should be unique within the system and stable across reboots + /// for the same hardware configuration. fn name(&self) -> &str; /// Returns the kind (category) of the device. -- Gitee