|
SimpleKernel 1.17.0
|
Virtio 块设备驱动 More...
#include <virtio_blk.hpp>

Classes | |
| struct | RequestSlot |
| 异步请求上下文槽 More... | |
Public Types | |
| using | UserData = void * |
| 异步 IO 回调中使用的用户自定义上下文指针类型 | |
Public Member Functions | |
| auto | EnqueueRead (uint16_t queue_index, uint64_t sector, const IoVec *buffers, size_t buffer_count, UserData token=nullptr) -> Expected< void > |
| 异步提交读请求(仅入队描述符,不触发硬件通知) | |
| auto | EnqueueWrite (uint16_t queue_index, uint64_t sector, const IoVec *buffers, size_t buffer_count, UserData token=nullptr) -> Expected< void > |
| 异步提交写请求(仅入队描述符,不触发硬件通知) | |
| auto | Kick (uint16_t queue_index) -> void |
| 批量触发硬件通知 | |
| template<typename CompletionCallback > | |
| auto | HandleInterrupt (CompletionCallback &&on_complete) -> void |
| 中断处理(带完成回调) | |
| auto | HandleInterrupt () -> void |
| 中断处理(简化版,无回调) | |
| auto | Read (uint64_t sector, uint8_t *data) -> Expected< void > |
| 同步读取一个扇区 | |
| auto | Write (uint64_t sector, const uint8_t *data) -> Expected< void > |
| 同步写入一个扇区 | |
| auto | ReadConfig () const -> BlkConfig |
| 读取块设备配置空间 | |
| auto | GetCapacity () const -> uint64_t |
| 获取设备容量 | |
| auto | GetNegotiatedFeatures () const -> uint64_t |
| 获取协商后的特性位 | |
| auto | GetStats () const -> VirtioStats |
| 获取性能监控统计数据 | |
构造/析构函数 | |
| VirtioBlk ()=delete | |
| VirtioBlk (VirtioBlk &&other) noexcept | |
| auto | operator= (VirtioBlk &&other) noexcept -> VirtioBlk & |
| VirtioBlk (const VirtioBlk &)=delete | |
| auto | operator= (const VirtioBlk &) -> VirtioBlk &=delete |
| ~VirtioBlk ()=default | |
Static Public Member Functions | |
| static constexpr auto | GetRequiredVqMemSize (uint16_t queue_count, uint32_t queue_size) -> std::pair< size_t, size_t > |
| 获取多队列所需的总 DMA 内存大小 | |
| static constexpr auto | CalcDmaSize (uint16_t queue_size=128) -> size_t |
| 计算单个 Virtqueue DMA 缓冲区所需的字节数(向后兼容) | |
| static constexpr auto | GetRequiredSlotMemSize () -> std::pair< size_t, size_t > |
| 计算 RequestSlot DMA 内存所需字节数 | |
| static auto | Create (uint64_t mmio_base, const DmaRegion &vq_dma, const DmaRegion &slot_dma, VirtToPhysFunc virt_to_phys=IdentityVirtToPhys, uint16_t queue_count=1, uint32_t queue_size=128, uint64_t driver_features=0) -> Expected< VirtioBlk > |
| 创建并初始化块设备 | |
Static Public Attributes | |
| static constexpr uint16_t | kMaxInflight = 64 |
| 每个设备的最大并发(in-flight)请求数 | |
| static constexpr size_t | kMaxSgElements = 18 |
| 每个 Scatter-Gather 请求的最大 IoVec 数量(含请求头和状态字节) | |
Private Member Functions | |
| VirtioBlk (TransportT transport, VirtqueueT vq, uint64_t features, const DmaRegion &slot_dma, VirtToPhysFunc v2p) | |
| 私有构造函数 | |
| auto | DoEnqueue (ReqType type, uint16_t queue_index, uint64_t sector, const IoVec *buffers, size_t buffer_count, UserData token) -> Expected< void > |
| 异步入队请求的内部实现 | |
| template<typename CompletionCallback > | |
| auto | ProcessCompletions (CompletionCallback &&on_complete) -> void |
| 处理 Used Ring 中已完成的请求 | |
| auto | AllocRequestSlot () -> Expected< uint16_t > |
| 从请求槽池中分配一个空闲槽(O(1) 位图算法) | |
| auto | FreeRequestSlot (uint16_t idx) -> void |
| 释放请求槽 | |
| auto | FindSlotByDescHead (uint16_t desc_head) const -> uint16_t |
| 根据描述符链头索引查找请求槽 | |
| auto | UpdateUsedEvent () -> void |
| 更新 avail->used_event 字段 | |
| auto | SubmitSyncRequest (ReqType type, uint64_t sector, const IoVec *buffers, size_t buffer_count) -> Expected< void > |
| 同步提交请求的内部实现 | |
Static Private Member Functions | |
| static auto | MapBlkStatus (uint8_t status) -> ErrorCode |
| 将设备 BlkStatus 映射为 ErrorCode | |
| static auto | VringNeedEvent (uint16_t event_idx, uint16_t new_idx, uint16_t old_idx) -> bool |
| 判断是否需要发送通知(处理 wrap-around) | |
Private Attributes | |
| TransportT | transport_ |
| 传输层实例 | |
| VirtqueueT | vq_ |
| Virtqueue 实例(当前支持单队列) | |
| uint64_t | negotiated_features_ {0} |
| 协商后的特性位掩码 | |
| DmaRegion | slot_dma_ {} |
| DMA region backing the request slot pool. | |
| RequestSlot * | slots_ {nullptr} |
| Pointer to request slot array (lives in slot_dma_ memory) | |
| VirtToPhysFunc | virt_to_phys_ {IdentityVirtToPhys} |
| Address translation callback. | |
| VirtioStats | stats_ |
| 性能统计数据 | |
| uint64_t | slot_bitmap_ {} |
| 请求槽占用位图(bit i = 1 表示 slots_[i] 被占用) | |
| uint16_t | old_avail_idx_ {0} |
| 上次 Kick 时的 avail idx(用于 Event Index 通知抑制) | |
| volatile bool | request_completed_ {false} |
| 请求完成标志(由简化版 HandleInterrupt 在中断上下文中设置) | |
Virtio 块设备驱动
virtio 块设备是一个简单的虚拟块设备(即磁盘)。 读写请求(以及其他特殊请求)被放置在请求队列中,由设备服务(可能乱序)。
该类封装了 VirtIO 块设备的完整生命周期:
用户只需提供 MMIO 基地址和 DMA 缓冲区, 即可通过 Read() / Write() 或异步接口进行块设备操作。
| TransportT | 传输层类型(默认 MmioTransport) |
| VirtqueueT | Virtqueue 类型(默认 SplitVirtqueue) |
| VirtqueueT | Virtqueue 模板(默认 SplitVirtqueue) |
Definition at line 50 of file virtio_blk.hpp.
| using virtio::blk::VirtioBlk< TransportT, VirtqueueT >::UserData = void* |
异步 IO 回调中使用的用户自定义上下文指针类型
Definition at line 53 of file virtio_blk.hpp.
|
delete |

|
inlinenoexcept |
Definition at line 479 of file virtio_blk.hpp.
|
delete |
|
default |
|
inlineprivate |
私有构造函数
只能通过 Create() 静态工厂方法创建实例。
Definition at line 539 of file virtio_blk.hpp.
|
inlineprivate |
从请求槽池中分配一个空闲槽(O(1) 位图算法)
使用 __builtin_ctzll 找到 slot_bitmap_ 中最低的 0 位。
Definition at line 679 of file virtio_blk.hpp.

|
inlinestaticconstexpr |
计算单个 Virtqueue DMA 缓冲区所需的字节数(向后兼容)
| queue_size | 队列大小(2 的幂,默认 128) |
Definition at line 86 of file virtio_blk.hpp.
|
inlinestatic |
创建并初始化块设备
内部自动完成:
| mmio_base | MMIO 设备基地址 |
| vq_dma | 预分配的 Virtqueue DMA 内存区域 (页对齐,已清零,大小 >= GetRequiredVqMemSize()) |
| slot_dma | 预分配的 RequestSlot DMA 内存区域 (大小 >= GetRequiredSlotMemSize()) |
| virt_to_phys | 虚拟地址到物理地址转换函数(默认恒等映射) |
| queue_count | 期望的队列数量(当前仅支持 1) |
| queue_size | 每个队列的描述符数量(2 的幂,默认 128) |
| driver_features | 额外的驱动特性位(VERSION_1 自动包含) |
Definition at line 122 of file virtio_blk.hpp.


|
inlineprivate |
异步入队请求的内部实现
分配请求槽,填充请求头,构建 Scatter-Gather 描述符链,提交到 Available Ring。
| type | 请求类型(kIn/kOut) |
| queue_index | 队列索引 |
| sector | 起始扇区号 |
| buffers | 数据缓冲区 IoVec 数组 |
| buffer_count | 缓冲区数量 |
| token | 用户上下文指针 |
Definition at line 566 of file virtio_blk.hpp.


|
inline |
异步提交读请求(仅入队描述符,不触发硬件通知)
构建 virtio-blk 请求描述符链(header + data buffers + status), 提交到 Available Ring,但不通知设备。调用者需随后调用 Kick() 通知。
| queue_index | 队列索引(当前仅支持 0) |
| sector | 起始扇区号(以 512 字节为单位) |
| buffers | 数据缓冲区 IoVec 数组(物理地址 + 长度) |
| buffer_count | buffers 数组中的元素数量 |
| token | 用户自定义上下文指针,在 HandleInterrupt 回调时原样传回 |
Definition at line 200 of file virtio_blk.hpp.

|
inline |
异步提交写请求(仅入队描述符,不触发硬件通知)
构建 virtio-blk 请求描述符链(header + data buffers + status), 提交到 Available Ring,但不通知设备。调用者需随后调用 Kick() 通知。
针对 Write 操作,数据缓冲区的描述符 flag 为设备只读(无 VRING_DESC_F_WRITE)。
| queue_index | 队列索引(当前仅支持 0) |
| sector | 起始扇区号(以 512 字节为单位) |
| buffers | 数据缓冲区 IoVec 数组(物理地址 + 长度) |
| buffer_count | buffers 数组中的元素数量 |
| token | 用户自定义上下文指针,在 HandleInterrupt 回调时原样传回 |
Definition at line 224 of file virtio_blk.hpp.

|
inlineprivate |
根据描述符链头索引查找请求槽
| desc_head | 描述符链头索引 |
Definition at line 709 of file virtio_blk.hpp.

|
inlineprivate |
释放请求槽
| idx | 槽索引 |
Definition at line 697 of file virtio_blk.hpp.

|
inline |
获取设备容量
Definition at line 454 of file virtio_blk.hpp.

|
inline |
|
inlinestaticconstexpr |
计算 RequestSlot DMA 内存所需字节数
Definition at line 97 of file virtio_blk.hpp.

|
inlinestaticconstexpr |
获取多队列所需的总 DMA 内存大小
调用者应根据此值预分配页对齐、已清零的 DMA 内存。
| queue_count | 请求的队列数量 |
| queue_size | 每个队列的描述符数量(必须为 2 的幂) |
Definition at line 71 of file virtio_blk.hpp.
|
inline |
|
inline |
中断处理(简化版,无回调)
仅确认设备中断并设置完成标志,供同步轮询使用。 不处理 Used Ring 和描述符回收。
Definition at line 300 of file virtio_blk.hpp.

|
inline |
中断处理(带完成回调)
在 ISR 或轮询循环中调用。确认设备中断,遍历 Used Ring 中已完成的请求, 对每个请求调用 on_complete 回调,释放描述符链和请求槽。
| CompletionCallback | 签名要求:void(UserData token, ErrorCode status)
|
| on_complete | 完成回调函数 |
Definition at line 279 of file virtio_blk.hpp.

|
inline |
批量触发硬件通知
通知设备 Available Ring 中有新的待处理请求。 调用者应在 EnqueueRead/EnqueueWrite 后调用此方法。
| queue_index | 队列索引(当前仅支持 0) |
Definition at line 240 of file virtio_blk.hpp.


|
inlinestaticprivate |
将设备 BlkStatus 映射为 ErrorCode
| status | 设备返回的原始状态字节 |
Definition at line 727 of file virtio_blk.hpp.

|
delete |
|
inlinenoexcept |
Definition at line 493 of file virtio_blk.hpp.
|
inlineprivate |
处理 Used Ring 中已完成的请求
遍历 Used Ring,对每个已完成的请求:
| CompletionCallback | void(UserData token, ErrorCode status) |
| on_complete | 完成回调 |
Definition at line 644 of file virtio_blk.hpp.


|
inline |
同步读取一个扇区
基于异步接口实现:EnqueueRead → Kick → 轮询 HandleInterrupt → 返回。
| sector | 起始扇区号(以 512 字节为单位) |
| data | 数据缓冲区(至少 kSectorSize 字节,必须位于 DMA 可访问内存) |
Definition at line 323 of file virtio_blk.hpp.


|
inline |
读取块设备配置空间
读取设备的配置信息,包括容量、几何信息、拓扑信息等。 配置空间的可用字段取决于协商的特性位。
Definition at line 365 of file virtio_blk.hpp.
|
inlineprivate |
同步提交请求的内部实现
Read()/Write() 的共享实现:入队 → Kick → 轮询等待 → 处理完成 → 返回。 轮询上限固定为 100000000 次迭代。
| type | 请求类型(kIn/kOut) |
| sector | 起始扇区号 |
| buffers | 数据缓冲区 IoVec 数组 |
| buffer_count | 缓冲区数量 |
Definition at line 788 of file virtio_blk.hpp.


|
inlineprivate |
更新 avail->used_event 字段
在处理完 Used Ring 后调用,告知设备下次在此索引之后再发送中断。 仅在协商了 VIRTIO_F_EVENT_IDX 时生效。
Definition at line 766 of file virtio_blk.hpp.


|
inlinestaticprivate |
判断是否需要发送通知(处理 wrap-around)
基于 virtio 规范中的 vring_need_event 算法:检查 event_idx 是否落在 (old, new] 区间内(含 uint16_t 回绕处理)。
| event_idx | 设备/驱动期望的通知阈值 |
| new_idx | 当前索引 |
| old_idx | 上次通知时的索引 |
Definition at line 752 of file virtio_blk.hpp.

|
inline |
同步写入一个扇区
基于异步接口实现:EnqueueWrite → Kick → 轮询 HandleInterrupt → 返回。
| sector | 起始扇区号(以 512 字节为单位) |
| data | 数据缓冲区(至少 kSectorSize 字节,必须位于 DMA 可访问内存) |
Definition at line 343 of file virtio_blk.hpp.


|
staticconstexpr |
每个设备的最大并发(in-flight)请求数
Definition at line 56 of file virtio_blk.hpp.
|
staticconstexpr |
每个 Scatter-Gather 请求的最大 IoVec 数量(含请求头和状态字节)
Definition at line 59 of file virtio_blk.hpp.
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
Pointer to request slot array (lives in slot_dma_ memory)
Definition at line 837 of file virtio_blk.hpp.
|
private |
性能统计数据
Definition at line 841 of file virtio_blk.hpp.
|
private |
传输层实例
Definition at line 829 of file virtio_blk.hpp.
|
private |
Address translation callback.
Definition at line 839 of file virtio_blk.hpp.
|
private |
Virtqueue 实例(当前支持单队列)
Definition at line 831 of file virtio_blk.hpp.