Skip to content

Commit 2bcde68

Browse files
committed
add qoder docs
1 parent 35da6c7 commit 2bcde68

17 files changed

+3132
-0
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# API参考
2+
3+
<cite>
4+
**本文档中引用的文件**
5+
- [lib.rs](file://src/lib.rs)
6+
- [Cargo.toml](file://Cargo.toml)
7+
- [README.md](file://README.md)
8+
</cite>
9+
10+
## 目录
11+
1. [简介](#简介)
12+
2. [模块结构与可见性规则](#模块结构与可见性规则)
13+
3. [核心公开类型](#核心公开类型)
14+
4. [BaseDeviceOps Trait 详细规格](#basedeviceops-trait-详细规格)
15+
5. [EmulatedDeviceConfig 结构体详细规格](#emulateddeviceconfig-结构体详细规格)
16+
6. [公开的Trait别名](#公开的trait别名)
17+
7. [辅助函数](#辅助函数)
18+
19+
## 简介
20+
21+
`axdevice_base` 库为 ArceOS 虚拟机管理程序(Hypervisor)中的虚拟设备子系统提供基础的抽象。该库旨在 `no_std` 环境下运行,定义了所有模拟设备必须实现的核心接口和配置结构。
22+
23+
本API参考文档旨在成为开发者日常查询的权威手册,详细记录了库中所有公开暴露的接口、结构体、枚举和函数。文档内容严格按照源码顺序组织,为每个条目提供精确的签名、字段描述、方法行为解释及错误类型说明。
24+
25+
**Section sources**
26+
- [lib.rs](file://src/lib.rs#L1-L83)
27+
- [README.md](file://README.md#L1-L45)
28+
29+
## 模块结构与可见性规则
30+
31+
`axdevice_base` 库目前采用扁平化的单文件模块结构。所有公共API均直接在根模块(即 `lib.rs` 文件)中定义和导出,没有使用嵌套的子模块。
32+
33+
### 可见性规则
34+
- 所有需要对外暴露的类型和函数均使用 `pub` 关键字声明。
35+
- 使用 `pub use` 语句从依赖项(如 `axvmconfig`)重新导出 `EmuDeviceType` 枚举,确保其对库的使用者是可见的。
36+
- 内部实现细节或测试代码(如 `#[cfg(test)] mod test;`)被明确标记为条件编译,不会暴露给外部用户。
37+
38+
这种设计简化了API的访问路径,开发者可以直接通过 `axdevice_base::TypeName` 的形式使用所有功能。
39+
40+
**Section sources**
41+
- [lib.rs](file://src/lib.rs#L1-L83)
42+
43+
## 核心公开类型
44+
45+
本节列出并描述 `axdevice_base` 库中所有公开的顶级类型。
46+
47+
```mermaid
48+
classDiagram
49+
class EmulatedDeviceConfig {
50+
+name : String
51+
+base_ipa : usize
52+
+length : usize
53+
+irq_id : usize
54+
+emu_type : usize
55+
+cfg_list : Vec<usize>
56+
+Default()
57+
}
58+
trait BaseDeviceOps~R~ {
59+
<<trait>>
60+
+emu_type() EmuDeviceType
61+
+address_range() R
62+
+handle_read(addr : R : : Addr, width : AccessWidth) AxResult<usize>
63+
+handle_write(addr : R : : Addr, width : AccessWidth, val : usize) AxResult
64+
}
65+
trait BaseMmioDeviceOps {
66+
<<trait alias>>
67+
= BaseDeviceOps<GuestPhysAddrRange>
68+
}
69+
trait BaseSysRegDeviceOps {
70+
<<trait alias>>
71+
= BaseDeviceOps<SysRegAddrRange>
72+
}
73+
trait BasePortDeviceOps {
74+
<<trait alias>>
75+
= BaseDeviceOps<PortRange>
76+
}
77+
EmulatedDeviceConfig : "Configuration for device initialization"
78+
BaseDeviceOps : "Core operations trait for all emulated devices"
79+
BaseMmioDeviceOps : "Alias for MMIO devices"
80+
BaseSysRegDeviceOps : "Alias for system register devices"
81+
BasePortDeviceOps : "Alias for port I/O devices"
82+
BaseMmioDeviceOps ..|> BaseDeviceOps : "aliases"
83+
BaseSysRegDeviceOps ..|> BaseDeviceOps : "aliases"
84+
BasePortDeviceOps ..|> BaseDeviceOps : "aliases"
85+
```
86+
87+
**Diagram sources**
88+
- [lib.rs](file://src/lib.rs#L32-L83)
89+
90+
**Section sources**
91+
- [lib.rs](file://src/lib.rs#L32-L83)
92+
93+
## BaseDeviceOps Trait 详细规格
94+
95+
`BaseDeviceOps` 是所有模拟设备必须实现的核心特质(trait)。它定义了一个设备的基本操作集,包括查询其类型、地址范围以及处理读写请求。
96+
97+
该特质是一个泛型特质,其类型参数 `R` 必须满足 `DeviceAddrRange` 约束,这允许特质根据不同的寻址方式(如内存映射I/O、端口I/O等)进行适配。
98+
99+
### 方法规格
100+
101+
#### emu_type
102+
- **签名**: `fn emu_type(&self) -> EmuDeviceType`
103+
- **行为**: 返回此设备实例所代表的设备类型。返回值来自 `axvmconfig` crate 中的 `EmuDeviceType` 枚举。
104+
- **副作用**: 无。
105+
- **有效性要求**: 此方法应始终成功返回一个有效的 `EmuDeviceType` 值,不应失败。
106+
107+
#### address_range
108+
- **签名**: `fn address_range(&self) -> R`
109+
- **行为**: 返回一个 `R` 类型的实例,表示该设备占用的地址空间范围。这个范围用于设备发现和路由I/O请求。
110+
- **副作用**: 无。
111+
- **有效性要求**: 返回的地址范围必须是有效且一致的,通常在设备创建时初始化后不应改变。
112+
113+
#### handle_read
114+
- **签名**: `fn handle_read(&self, addr: R::Addr, width: AccessWidth) -> AxResult<usize>`
115+
- **行为**: 处理对设备的读取操作。`addr` 是相对于设备基地址的偏移量,`width` 指定了读取的数据宽度(如8位、16位、32位等)。
116+
- **返回值**: 成功时返回 `AxResult<usize>`,其中 `usize` 包含从设备寄存器读取到的值。失败时返回一个 `AxError` 错误码。
117+
- **可能抛出的错误**: 实现者可以根据具体情况返回各种 `AxError`,例如 `InvalidInput`(无效地址或宽度)、`NotSupported`(不支持的操作)等。
118+
- **有效性要求**: `addr` 必须在 `address_range()` 返回的范围内,`width` 必须是设备支持的有效宽度。
119+
120+
#### handle_write
121+
- **签名**: `fn handle_write(&self, addr: R::Addr, width: AccessWidth, val: usize) -> AxResult`
122+
- **行为**: 处理对设备的写入操作。`addr` 是相对于设备基地址的偏移量,`width` 指定了写入的数据宽度,`val` 是要写入的值。
123+
- **返回值**: 成功时返回 `Ok(())`,失败时返回一个 `AxError` 错误码。
124+
- **可能抛出的错误**: 同 `handle_read`,可能因无效输入、不支持的操作或设备内部状态问题而失败。
125+
- **副作用**: 此方法可能会改变设备的内部状态,例如更新控制寄存器、触发中断或启动数据传输。
126+
- **有效性要求**: `addr``width` 的有效性要求同 `handle_read`
127+
128+
**Section sources**
129+
- [lib.rs](file://src/lib.rs#L48-L59)
130+
131+
## EmulatedDeviceConfig 结构体详细规格
132+
133+
`EmulatedDeviceConfig` 结构体用于在虚拟机创建时配置一个模拟设备的初始参数。
134+
135+
```rust
136+
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
137+
pub struct EmulatedDeviceConfig {
138+
pub name: String,
139+
pub base_ipa: usize,
140+
pub length: usize,
141+
pub irq_id: usize,
142+
pub emu_type: usize,
143+
pub cfg_list: Vec<usize>,
144+
}
145+
```
146+
147+
### 字段描述
148+
149+
- **`name`** (`String`): 设备的名称。这是一个必填项,用于标识和日志记录。
150+
- **`base_ipa`** (`usize`): 设备的基中间物理地址(Intermediate Physical Address)。这是设备在客户机物理地址空间中的起始地址,为必填项。
151+
- **`length`** (`usize`): 设备占用的地址空间长度(以字节为单位)。必须大于0,为必填项。
152+
- **`irq_id`** (`usize`): 设备使用的中断请求(IRQ)ID。当设备需要向虚拟CPU发送中断时使用,为必填项。
153+
- **`emu_type`** (`usize`): 设备类型的数值表示。虽然类型为 `usize`,但它应对应于 `EmuDeviceType` 枚举中的某个变体。此字段为必填项。
154+
- **`cfg_list`** (`Vec<usize>`): 设备的配置列表,用于传递特定于设备的额外配置参数。此字段没有默认值,但可以为空向量 `Vec::new()`
155+
156+
### 默认值
157+
该结构体实现了 `Default` 特质。调用 `EmulatedDeviceConfig::default()` 将创建一个所有字段都为空或零值的实例:
158+
- `name`: 空字符串 `String::new()`
159+
- `base_ipa`: `0`
160+
- `length`: `0`
161+
- `irq_id`: `0`
162+
- `emu_type`: `0`
163+
- `cfg_list`: 空向量 `Vec::new()`
164+
165+
**注意**: 尽管提供了默认值,但在实际使用中,大多数字段都需要显式设置有效值才能正确初始化设备。
166+
167+
**Section sources**
168+
- [lib.rs](file://src/lib.rs#L32-L46)
169+
170+
## 公开的Trait别名
171+
172+
为了方便使用,`axdevice_base` 定义了几个基于 `BaseDeviceOps` 的公开Trait别名,分别对应不同类型的设备。
173+
174+
### BaseMmioDeviceOps
175+
- **展开形式**: `BaseDeviceOps<GuestPhysAddrRange>`
176+
- **用途**: 该别名专门用于内存映射I/O(MMIO)设备。它将 `BaseDeviceOps` 的泛型参数 `R` 固定为 `GuestPhysAddrRange`,简化了针对此类设备的类型声明和边界。
177+
178+
### BaseSysRegDeviceOps
179+
- **展开形式**: `BaseDeviceOps<SysRegAddrRange>`
180+
- **用途**: 该别名用于模拟系统寄存器的设备。它将泛型参数 `R` 固定为 `SysRegAddrRange`
181+
182+
### BasePortDeviceOps
183+
- **展开形式**: `BaseDeviceOps<PortRange>`
184+
- **用途**: 该别名用于传统的端口I/O(Port I/O)设备。它将泛型参数 `R` 固定为 `PortRange`
185+
186+
这些Trait别名利用了Rust的 `#![feature(trait_alias)]` 功能,提高了代码的可读性和易用性。
187+
188+
**Section sources**
189+
- [lib.rs](file://src/lib.rs#L73-L80)
190+
191+
## 辅助函数
192+
193+
### map_device_of_type
194+
- **签名**:
195+
```rust
196+
pub fn map_device_of_type<T: BaseDeviceOps<R>, R: DeviceAddrRange, U, F: FnOnce(&T) -> U>(
197+
device: &Arc<dyn BaseDeviceOps<R>>,
198+
f: F,
199+
) -> Option<U>
200+
```
201+
- **行为**: 该函数尝试将一个动态分发的设备引用(`Arc<dyn BaseDeviceOps<R>>`)向下转换为其具体类型 `T`。如果转换成功,则调用提供的闭包 `f` 并返回其结果;如果类型不匹配,则返回 `None`。
202+
- **用途**: 在需要对特定类型的设备执行操作时非常有用,例如访问只有特定设备才有的专有方法。
203+
- **示例**: 可以用来安全地访问一个自定义设备的私有配置或状态,前提是已知其具体类型。
204+
- **稳定性**: 这是一个稳定且安全的API,利用了Rust的 `Any` 特质和动态类型转换机制。
205+
206+
**Section sources**
207+
- [lib.rs](file://src/lib.rs#L61-L71)
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# 快速开始
2+
3+
<cite>
4+
**本文档中引用的文件**
5+
- [Cargo.toml](file://Cargo.toml)
6+
- [src/lib.rs](file://src/lib.rs)
7+
- [src/test.rs](file://src/test.rs)
8+
- [README.md](file://README.md)
9+
</cite>
10+
11+
## 目录
12+
1. [简介](#简介)
13+
2. [环境准备与依赖配置](#环境准备与依赖配置)
14+
3. [定义虚拟设备结构体](#定义虚拟设备结构体)
15+
4. [实现BaseDeviceOps trait](#实现basedeviceops-trait)
16+
5. [创建设备配置实例](#创建设备配置实例)
17+
6. [验证类型转换功能](#验证类型转换功能)
18+
7. [常见构建错误与解决方案](#常见构建错误与解决方案)
19+
8. [推荐开发工具链](#推荐开发工具链)
20+
21+
## 简介
22+
本指南旨在帮助开发者快速上手 `axdevice_base` 库,用于在 ArceOS 超级管理程序(hypervisor)环境中开发和集成虚拟设备。通过本教程,您将学习如何设置开发环境、定义一个简单的虚拟设备、实现核心操作接口,并验证关键功能。所有示例均基于库中提供的实际代码模式。
23+
24+
## 环境准备与依赖配置
25+
26+
在开始之前,您需要确保您的 Rust 开发环境已正确安装。`axdevice_base` 是一个为 `no_std` 环境设计的库,因此它不依赖于标准库。
27+
28+
要将 `axdevice_base` 添加到您的项目中,请在 `Cargo.toml` 文件的 `[dependencies]` 部分添加以下内容:
29+
30+
```toml
31+
[dependencies]
32+
axdevice_base = { path = "d:\\project\\qcoder\\axdevice_base" }
33+
```
34+
35+
该库依赖于 ArceOS 项目的一系列 crate,如 `axerrno`, `axaddrspace`, 和 `axvmconfig`。这些依赖已在 `axdevice_base``Cargo.toml` 中声明,版本号为 `0.1.0`,确保了版本兼容性。同时,该库启用了 `serde``derive``alloc` 特性以支持序列化和堆内存分配。
36+
37+
**Section sources**
38+
- [Cargo.toml](file://Cargo.toml#L10-L18)
39+
40+
## 定义虚拟设备结构体
41+
42+
第一步是定义一个表示您虚拟设备的 Rust 结构体。这个结构体将包含设备的所有状态信息。在下面的例子中,我们定义了一个名为 `MyDevice` 的简单设备,目前它不包含任何特定的状态字段。
43+
44+
```rust
45+
struct MyDevice;
46+
```
47+
48+
这是一个最简化的形式。在实际应用中,您可以在此结构体中添加字段来存储设备寄存器、缓冲区或其他运行时数据。
49+
50+
**Section sources**
51+
- [src/test.rs](file://src/test.rs#L9)
52+
53+
## 实现BaseDeviceOps trait
54+
55+
所有虚拟设备都必须实现 `BaseDeviceOps` trait。这是一个核心接口,定义了设备的基本行为。您需要为您的设备结构体提供此 trait 的具体实现。
56+
57+
```rust
58+
impl BaseDeviceOps<GuestPhysAddrRange> for MyDevice {
59+
fn emu_type(&self) -> EmuDeviceType {
60+
EmuDeviceType::Dummy
61+
}
62+
63+
fn address_range(&self) -> GuestPhysAddrRange {
64+
(0x1000..0x2000).try_into().unwrap()
65+
}
66+
67+
fn handle_read(&self, addr: GuestPhysAddr, _width: AccessWidth) -> AxResult<usize> {
68+
Ok(addr.as_usize())
69+
}
70+
71+
fn handle_write(&self, _addr: GuestPhysAddr, _width: AccessWidth, _val: usize) -> AxResult {
72+
Ok(())
73+
}
74+
}
75+
```
76+
77+
### 关键语法点解释:
78+
- **泛型参数 `<GuestPhysAddrRange>`**: 指定此设备是一个 MMIO 设备,其地址范围由 `GuestPhysAddrRange` 表示。
79+
- **`emu_type` 方法**: 返回设备的类型枚举值。在此示例中使用了 `EmuDeviceType::Dummy`
80+
- **`address_range` 方法**: 定义设备在客户机物理地址空间中的映射范围,此处为 `0x1000``0x2000`
81+
- **`handle_read``handle_write` 方法**: 处理对设备的读写访问。`handle_read` 返回被读取的地址值,`handle_write` 接受写入的值但不执行任何操作。
82+
83+
**Section sources**
84+
- [src/lib.rs](file://src/lib.rs#L55-L67)
85+
- [src/test.rs](file://src/test.rs#L11-L31)
86+
87+
## 创建设备配置实例
88+
89+
`EmulatedDeviceConfig` 结构体用于在虚拟机启动时配置设备。您可以使用其默认构造函数并根据需要修改字段。
90+
91+
```rust
92+
let config = EmulatedDeviceConfig {
93+
name: "my_device".to_string(),
94+
base_ipa: 0x1000,
95+
length: 0x1000,
96+
irq_id: 5,
97+
emu_type: EmuDeviceType::Dummy as usize,
98+
cfg_list: vec![],
99+
};
100+
```
101+
102+
此配置指定了设备名称、基地址、长度、中断请求 ID 和设备类型等信息。
103+
104+
**Section sources**
105+
- [src/lib.rs](file://src/lib.rs#L40-L53)
106+
107+
## 验证类型转换功能
108+
109+
`map_device_of_type` 函数允许您安全地检查一个 `Arc<dyn BaseDeviceOps>` 是否指向特定类型的设备(例如 `MyDevice`),并在确认后调用该类型特有的方法。
110+
111+
```rust
112+
// 假设 devices 是一个包含各种设备的向量
113+
for device in &devices {
114+
if let Some(my_device) = map_device_of_type::<MyDevice, _, _, _>(device, |d| d) {
115+
// 此处可以安全地调用 MyDevice 的特有方法
116+
my_device.test_method();
117+
}
118+
}
119+
```
120+
121+
`src/test.rs` 中有一个完整的测试用例,展示了如何使用 `map_device_of_type` 来识别 `DeviceA` 并调用其独有的 `test_method()` 方法。
122+
123+
```mermaid
124+
sequenceDiagram
125+
participant Main as 主程序
126+
participant MapFunc as map_device_of_type
127+
participant Device as Arc<dyn BaseDeviceOps>
128+
Main->>MapFunc : 调用 map_device_of_type(device, |d| d.test_method())
129+
MapFunc->>Device : clone() 获取 Any 类型的 Arc
130+
MapFunc->>MapFunc : 尝试 downcast_ref : : <DeviceA>()
131+
alt 转换成功
132+
MapFunc->>MapFunc : 执行闭包 f(d)
133+
MapFunc->>Main : 返回 Some(result)
134+
else 转换失败
135+
MapFunc->>Main : 返回 None
136+
end
137+
```
138+
139+
**Diagram sources**
140+
- [src/lib.rs](file://src/lib.rs#L69-L83)
141+
- [src/test.rs](file://src/test.rs#L45-L74)
142+
143+
**Section sources**
144+
- [src/lib.rs](file://src/lib.rs#L69-L83)
145+
- [src/test.rs](file://src/test.rs#L45-L74)
146+
147+
## 常见构建错误与解决方案
148+
149+
在集成 `axdevice_base` 时,可能会遇到以下常见错误:
150+
151+
1. **缺少 feature gate 错误**:
152+
* **错误信息**: `error[E0658]: the `#![feature(...)]` attribute is an experimental feature`
153+
* **原因**: `axdevice_base` 使用了 `#![feature(trait_alias)]`, `#![feature(trait_upcasting)]`, 和 `#![feature(generic_const_exprs)]` 这些不稳定特性。
154+
* **解决方案**: 确保您的项目也启用了这些特性。在您的 `lib.rs``main.rs` 的顶部添加 `#![feature(trait_alias, trait_upcasting, generic_const_exprs)]`
155+
156+
2. **链接或未解析的符号错误**:
157+
* **错误信息**: `undefined reference to ...``linking with 'cc' failed`
158+
* **原因**: 通常是因为 `no_std` 环境下缺少必要的运行时或内存分配器。
159+
* **解决方案**: 确保您的二进制项目(bin crate)正确链接了 `std` 或实现了 `panic_handler``oom` 等必需的 `no_std` 组件,并且正确配置了全局分配器(如 `global_allocator`)。
160+
161+
3. **版本冲突**:
162+
* **错误信息**: `failed to select a version for `axaddrspace``
163+
* **原因**: 项目中其他依赖项要求的 ArceOS crate 版本与 `axdevice_base` 不兼容。
164+
* **解决方案**: 检查 `axdevice_base/Cargo.toml` 中声明的版本(如 `axaddrspace = "0.1.0"`),并确保您的工作区中所有相关 crate 都使用相同版本,或使用 Cargo 的 `[patch]` 功能进行版本统一。
165+
166+
## 推荐开发工具链
167+
168+
为了获得最佳的开发体验,建议使用以下工具链:
169+
170+
- **Rust 工具链**: 使用最新的稳定版 Rust 编译器(`rustc`)。由于库使用了不稳定特性,可能需要 nightly 版本,但请参考官方文档确认最低支持版本。
171+
- **IDE 支持**: 推荐使用 Visual Studio Code 配合 `rust-analyzer` 插件。确保 `rust-analyzer` 配置为使用正确的 Rust toolchain(nightly 或 stable)。
172+
- **测试环境**: 使用 `qemu-system-aarch64` 来模拟 AArch64 架构,这是 ArceOS 的主要目标平台。配置 QEMU 启动脚本以加载您的内核镜像并传递必要的设备树或 ACPI 表。
173+
- **调试工具**: 结合 `gdb` 和 QEMU 的远程调试功能,可以在源码级别调试虚拟设备的执行流程。
174+
175+
遵循本指南,您应该能够成功搭建开发环境并完成第一个基于 `axdevice_base` 的虚拟设备集成。

0 commit comments

Comments
 (0)