SimpleKernel 1.17.0
Loading...
Searching...
No Matches
virtio::blk::VirtioBlk< TransportT, VirtqueueT > Class Template Reference

Virtio 块设备驱动 More...

#include <virtio_blk.hpp>

Collaboration diagram for virtio::blk::VirtioBlk< TransportT, VirtqueueT >:
Collaboration graph

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.
 
RequestSlotslots_ {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 在中断上下文中设置)
 

Detailed Description

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
class virtio::blk::VirtioBlk< TransportT, VirtqueueT >

Virtio 块设备驱动

virtio 块设备是一个简单的虚拟块设备(即磁盘)。 读写请求(以及其他特殊请求)被放置在请求队列中,由设备服务(可能乱序)。

该类封装了 VirtIO 块设备的完整生命周期:

  • 传输层的创建和管理(通过 TransportT 模板参数泛化)
  • Virtqueue 的创建和管理(通过 VirtqueueT 模板参数泛化)
  • 设备初始化序列(特性协商、队列配置、设备激活)
  • 异步 IO 接口(Enqueue/Kick/HandleInterrupt 回调模型)
  • 同步读写便捷方法(基于异步接口实现)

用户只需提供 MMIO 基地址和 DMA 缓冲区, 即可通过 Read() / Write() 或异步接口进行块设备操作。

Template Parameters
TransportT传输层类型(默认 MmioTransport)
VirtqueueTVirtqueue 类型(默认 SplitVirtqueue)
VirtqueueTVirtqueue 模板(默认 SplitVirtqueue)
See also
virtio-v1.2#5.2 Block Device
架构文档 §3

Definition at line 50 of file virtio_blk.hpp.

Member Typedef Documentation

◆ UserData

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
using virtio::blk::VirtioBlk< TransportT, VirtqueueT >::UserData = void*

异步 IO 回调中使用的用户自定义上下文指针类型

Definition at line 53 of file virtio_blk.hpp.

Constructor & Destructor Documentation

◆ VirtioBlk() [1/4]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
virtio::blk::VirtioBlk< TransportT, VirtqueueT >::VirtioBlk ( )
delete
Here is the caller graph for this function:

◆ VirtioBlk() [2/4]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
virtio::blk::VirtioBlk< TransportT, VirtqueueT >::VirtioBlk ( VirtioBlk< TransportT, VirtqueueT > &&  other)
inlinenoexcept

Definition at line 479 of file virtio_blk.hpp.

480 : transport_(std::move(other.transport_)),
481 vq_(std::move(other.vq_)),
482 negotiated_features_(other.negotiated_features_),
483 slot_dma_(other.slot_dma_),
484 slots_(other.slots_),
485 virt_to_phys_(other.virt_to_phys_),
486 stats_(other.stats_),
487 slot_bitmap_(other.slot_bitmap_),
488 old_avail_idx_(other.old_avail_idx_),
489 request_completed_(other.request_completed_) {
490 other.slots_ = nullptr;
491 other.slot_bitmap_ = 0;
492 }
VirtToPhysFunc virt_to_phys_
Address translation callback.
volatile bool request_completed_
请求完成标志(由简化版 HandleInterrupt 在中断上下文中设置)
RequestSlot * slots_
Pointer to request slot array (lives in slot_dma_ memory)
VirtqueueT vq_
Virtqueue 实例(当前支持单队列)
uint16_t old_avail_idx_
上次 Kick 时的 avail idx(用于 Event Index 通知抑制)
uint64_t negotiated_features_
协商后的特性位掩码
TransportT transport_
传输层实例
VirtioStats stats_
性能统计数据
uint64_t slot_bitmap_
请求槽占用位图(bit i = 1 表示 slots_[i] 被占用)
DmaRegion slot_dma_
DMA region backing the request slot pool.

◆ VirtioBlk() [3/4]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
virtio::blk::VirtioBlk< TransportT, VirtqueueT >::VirtioBlk ( const VirtioBlk< TransportT, VirtqueueT > &  )
delete

◆ ~VirtioBlk()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
virtio::blk::VirtioBlk< TransportT, VirtqueueT >::~VirtioBlk ( )
default

◆ VirtioBlk() [4/4]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
virtio::blk::VirtioBlk< TransportT, VirtqueueT >::VirtioBlk ( TransportT  transport,
VirtqueueT  vq,
uint64_t  features,
const DmaRegion slot_dma,
VirtToPhysFunc  v2p 
)
inlineprivate

私有构造函数

只能通过 Create() 静态工厂方法创建实例。

Definition at line 539 of file virtio_blk.hpp.

541 : transport_(std::move(transport)),
542 vq_(std::move(vq)),
543 negotiated_features_(features),
544 slot_dma_(slot_dma),
545 slots_(reinterpret_cast<RequestSlot*>(slot_dma.Data())),
546 virt_to_phys_(v2p),
547 stats_{},
548 slot_bitmap_(0),
550 request_completed_(false) {}
auto Data() const -> uint8_t *
获取虚拟基地址的类型化指针
Definition io_buffer.hpp:52

Member Function Documentation

◆ AllocRequestSlot()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::AllocRequestSlot ( ) -> Expected<uint16_t>
inlineprivate

从请求槽池中分配一个空闲槽(O(1) 位图算法)

使用 __builtin_ctzll 找到 slot_bitmap_ 中最低的 0 位。

Returns
成功返回槽索引,失败返回错误

Definition at line 679 of file virtio_blk.hpp.

679 {
680 uint64_t free_bits = ~slot_bitmap_;
681 if (free_bits == 0) {
682 return std::unexpected(Error{ErrorCode::kNoFreeDescriptors});
683 }
684 auto idx = static_cast<uint16_t>(__builtin_ctzll(free_bits));
685 if (idx >= kMaxInflight) {
686 return std::unexpected(Error{ErrorCode::kNoFreeDescriptors});
687 }
688 slot_bitmap_ |= (uint64_t{1} << idx);
689 return idx;
690 }
static constexpr uint16_t kMaxInflight
每个设备的最大并发(in-flight)请求数
@ kNoFreeDescriptors
没有空闲描述符
错误类型,用于 std::expected
Definition expected.hpp:343
Here is the caller graph for this function:

◆ CalcDmaSize()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
static constexpr auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::CalcDmaSize ( uint16_t  queue_size = 128) -> size_t
inlinestaticconstexpr

计算单个 Virtqueue DMA 缓冲区所需的字节数(向后兼容)

Parameters
queue_size队列大小(2 的幂,默认 128)
Returns
所需的 DMA 内存字节数

Definition at line 86 of file virtio_blk.hpp.

87 {
88 // 始终按 event_idx=true 分配,确保空间充足
89 return VirtqueueT::CalcSize(queue_size, true);
90 }

◆ Create()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
static auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::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>
inlinestatic

创建并初始化块设备

内部自动完成:

  1. Transport 初始化和验证
  2. Virtqueue 创建
  3. VirtIO 设备初始化序列(重置、特性协商、队列配置、设备激活)
Parameters
mmio_baseMMIO 设备基地址
vq_dma预分配的 Virtqueue DMA 内存区域 (页对齐,已清零,大小 >= GetRequiredVqMemSize()
slot_dma预分配的 RequestSlot DMA 内存区域 (大小 >= GetRequiredSlotMemSize()
virt_to_phys虚拟地址到物理地址转换函数(默认恒等映射)
queue_count期望的队列数量(当前仅支持 1)
queue_size每个队列的描述符数量(2 的幂,默认 128)
driver_features额外的驱动特性位(VERSION_1 自动包含)
Returns
成功返回 VirtioBlk 实例,失败返回错误
See also
virtio-v1.2#3.1.1 Driver Requirements: Device Initialization

Definition at line 122 of file virtio_blk.hpp.

126 {
127 if (queue_count == 0) {
128 return std::unexpected(Error{ErrorCode::kInvalidArgument});
129 }
130 if (queue_count > 1) {
131 }
132
133 // 1. 创建传输层
134 TransportT transport(mmio_base);
135 if (!transport.IsValid()) {
136 return std::unexpected(Error{ErrorCode::kTransportNotInitialized});
137 }
138
139 // 2. 设备初始化序列
140 DeviceInitializer<TransportT> initializer(transport);
141
142 uint64_t wanted_features =
143 static_cast<uint64_t>(ReservedFeature::kVersion1) |
144 static_cast<uint64_t>(ReservedFeature::kEventIdx) | driver_features;
145 auto negotiated_result = initializer.Init(wanted_features);
146 if (!negotiated_result) {
147 return std::unexpected(negotiated_result.error());
148 }
149 uint64_t negotiated = *negotiated_result;
150
151 if ((negotiated & static_cast<uint64_t>(ReservedFeature::kVersion1)) == 0) {
152 return std::unexpected(Error{ErrorCode::kFeatureNegotiationFailed});
153 }
154
155 // 根据协商结果决定是否启用 Event Index
156 bool event_idx =
157 (negotiated & static_cast<uint64_t>(ReservedFeature::kEventIdx)) != 0;
158 if (event_idx) {
159 }
160 // 3. 创建 Virtqueue
161 VirtqueueT vq(vq_dma, static_cast<uint16_t>(queue_size), event_idx);
162 if (!vq.IsValid()) {
163 return std::unexpected(Error{ErrorCode::kInvalidArgument});
164 }
165
166 // 4. 配置队列
167 const uint32_t queue_idx = 0;
168 auto setup_result = initializer.SetupQueue(
169 queue_idx, vq.DescPhys(), vq.AvailPhys(), vq.UsedPhys(), vq.Size());
170 if (!setup_result) {
171 return std::unexpected(setup_result.error());
172 }
173
174 // 5. 激活设备
175 auto activate_result = initializer.Activate();
176 if (!activate_result) {
177 return std::unexpected(activate_result.error());
178 }
179
180 return VirtioBlk(std::move(transport), std::move(vq), negotiated, slot_dma,
181 virt_to_phys);
182 }
@ kTransportNotInitialized
传输层未正确初始化
@ kFeatureNegotiationFailed
特性协商失败
@ kInvalidArgument
@ kEventIdx
设备支持 avail_event 和 used_event 字段 (VIRTIO_F_EVENT_IDX) [1 << 29]
@ kVersion1
设备符合 virtio 1.0+ 规范 (VIRTIO_F_VERSION_1) [1 << 32]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoEnqueue()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::DoEnqueue ( ReqType  type,
uint16_t  queue_index,
uint64_t  sector,
const IoVec buffers,
size_t  buffer_count,
UserData  token 
) -> Expected<void>
inlineprivate

异步入队请求的内部实现

分配请求槽,填充请求头,构建 Scatter-Gather 描述符链,提交到 Available Ring。

Parameters
type请求类型(kIn/kOut)
queue_index队列索引
sector起始扇区号
buffers数据缓冲区 IoVec 数组
buffer_count缓冲区数量
token用户上下文指针
Returns
成功或失败

Definition at line 566 of file virtio_blk.hpp.

569 {
570 if (queue_index != 0) {
571 return std::unexpected(Error{ErrorCode::kInvalidArgument});
572 }
573
574 if (buffer_count + 2 > kMaxSgElements) {
575 return std::unexpected(Error{ErrorCode::kInvalidArgument});
576 }
577
578 auto slot_result = AllocRequestSlot();
579 if (!slot_result) {
581 return std::unexpected(slot_result.error());
582 }
583 uint16_t slot_idx = *slot_result;
584 auto& slot = slots_[slot_idx];
585
586 slot.header.type = static_cast<uint32_t>(type);
587 slot.header.reserved = 0;
588 slot.header.sector = sector;
589 slot.status = 0xFF; // sentinel:设备完成后会覆写
590 slot.token = token;
591
592 std::array<IoVec, kMaxSgElements> readable_iovs{};
593 std::array<IoVec, kMaxSgElements> writable_iovs{};
594 size_t readable_count = 0;
595 size_t writable_count = 0;
596
597 auto slot_base_phys =
598 slot_dma_.phys + static_cast<size_t>(slot_idx) * sizeof(RequestSlot);
599 readable_iovs[readable_count++] = {
600 slot_base_phys + offsetof(RequestSlot, header), sizeof(BlkReqHeader)};
601
602 if (type == ReqType::kIn) {
603 for (size_t i = 0; i < buffer_count; ++i) {
604 writable_iovs[writable_count++] = buffers[i];
605 }
606 } else {
607 for (size_t i = 0; i < buffer_count; ++i) {
608 readable_iovs[readable_count++] = buffers[i];
609 }
610 }
611
612 // 状态字节始终为 device-writable
613 writable_iovs[writable_count++] = {
614 slot_base_phys + offsetof(RequestSlot, status), sizeof(uint8_t)};
615
616 cpu_io::Wmb();
617
618 auto chain_result = vq_.SubmitChain(readable_iovs.data(), readable_count,
619 writable_iovs.data(), writable_count);
620 if (!chain_result) {
621 FreeRequestSlot(slot_idx);
623 return std::unexpected(chain_result.error());
624 }
625
626 slot.desc_head = *chain_result;
627
628 return {};
629 }
auto AllocRequestSlot() -> Expected< uint16_t >
从请求槽池中分配一个空闲槽(O(1) 位图算法)
auto FreeRequestSlot(uint16_t idx) -> void
释放请求槽
static constexpr size_t kMaxSgElements
每个 Scatter-Gather 请求的最大 IoVec 数量(含请求头和状态字节)
void Wmb()
Definition cpu_io.h:58
@ kIn
读取 (VIRTIO_BLK_T_IN)
uintptr_t phys
物理(总线/DMA)基地址
Definition io_buffer.hpp:41
uint32_t type
请求类型 (ReqType)
BlkReqHeader header
请求头(DMA 可访问,设备只读)
uint64_t queue_full_errors
队列满导致入队失败的次数
Here is the call graph for this function:
Here is the caller graph for this function:

◆ EnqueueRead()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::EnqueueRead ( uint16_t  queue_index,
uint64_t  sector,
const IoVec buffers,
size_t  buffer_count,
UserData  token = nullptr 
) -> Expected<void>
inline

异步提交读请求(仅入队描述符,不触发硬件通知)

构建 virtio-blk 请求描述符链(header + data buffers + status), 提交到 Available Ring,但不通知设备。调用者需随后调用 Kick() 通知。

Parameters
queue_index队列索引(当前仅支持 0)
sector起始扇区号(以 512 字节为单位)
buffers数据缓冲区 IoVec 数组(物理地址 + 长度)
buffer_countbuffers 数组中的元素数量
token用户自定义上下文指针,在 HandleInterrupt 回调时原样传回
Returns
成功或失败
See also
virtio-v1.2#5.2.6 Device Operation

Definition at line 200 of file virtio_blk.hpp.

202 {
203 return DoEnqueue(ReqType::kIn, queue_index, sector, buffers, buffer_count,
204 token);
205 }
auto DoEnqueue(ReqType type, uint16_t queue_index, uint64_t sector, const IoVec *buffers, size_t buffer_count, UserData token) -> Expected< void >
异步入队请求的内部实现
Here is the call graph for this function:

◆ EnqueueWrite()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::EnqueueWrite ( uint16_t  queue_index,
uint64_t  sector,
const IoVec buffers,
size_t  buffer_count,
UserData  token = nullptr 
) -> Expected<void>
inline

异步提交写请求(仅入队描述符,不触发硬件通知)

构建 virtio-blk 请求描述符链(header + data buffers + status), 提交到 Available Ring,但不通知设备。调用者需随后调用 Kick() 通知。

针对 Write 操作,数据缓冲区的描述符 flag 为设备只读(无 VRING_DESC_F_WRITE)。

Parameters
queue_index队列索引(当前仅支持 0)
sector起始扇区号(以 512 字节为单位)
buffers数据缓冲区 IoVec 数组(物理地址 + 长度)
buffer_countbuffers 数组中的元素数量
token用户自定义上下文指针,在 HandleInterrupt 回调时原样传回
Returns
成功或失败
See also
virtio-v1.2#5.2.6 Device Operation

Definition at line 224 of file virtio_blk.hpp.

226 {
227 return DoEnqueue(ReqType::kOut, queue_index, sector, buffers, buffer_count,
228 token);
229 }
@ kOut
写入 (VIRTIO_BLK_T_OUT)
Here is the call graph for this function:

◆ FindSlotByDescHead()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::FindSlotByDescHead ( uint16_t  desc_head) const -> uint16_t
inlineprivate

根据描述符链头索引查找请求槽

Parameters
desc_head描述符链头索引
Returns
匹配的槽索引,未找到则返回 kMaxInflight

Definition at line 709 of file virtio_blk.hpp.

709 {
710 uint64_t used = slot_bitmap_;
711 while (used != 0) {
712 auto i = static_cast<uint16_t>(__builtin_ctzll(used));
713 if (slots_[i].desc_head == desc_head) {
714 return i;
715 }
716 used &= used - 1; // clear lowest set bit
717 }
718 return kMaxInflight;
719 }
Here is the caller graph for this function:

◆ FreeRequestSlot()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::FreeRequestSlot ( uint16_t  idx) -> void
inlineprivate

释放请求槽

Parameters
idx槽索引

Definition at line 697 of file virtio_blk.hpp.

697 {
698 if (idx < kMaxInflight) {
699 slot_bitmap_ &= ~(uint64_t{1} << idx);
700 }
701 }
Here is the caller graph for this function:

◆ GetCapacity()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::GetCapacity ( ) const -> uint64_t
inline

获取设备容量

Returns
设备容量(以 512 字节扇区为单位)
See also
virtio-v1.2#5.2.4

Definition at line 454 of file virtio_blk.hpp.

454 {
455 return transport_.ReadConfigU64(
456 static_cast<uint32_t>(BlkConfigOffset::kCapacity));
457 }
Here is the caller graph for this function:

◆ GetNegotiatedFeatures()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::GetNegotiatedFeatures ( ) const -> uint64_t
inline

获取协商后的特性位

Returns
设备和驱动程序都支持的特性位掩码

Definition at line 464 of file virtio_blk.hpp.

464 {
466 }

◆ GetRequiredSlotMemSize()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
static constexpr auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::GetRequiredSlotMemSize ( ) -> std::pair<size_t, size_t>
inlinestaticconstexpr

计算 RequestSlot DMA 内存所需字节数

Returns
pair.first = 总字节数,pair.second = 对齐要求(字节)

Definition at line 97 of file virtio_blk.hpp.

98 {
99 return {sizeof(RequestSlot) * kMaxInflight, alignof(RequestSlot)};
100 }
Here is the caller graph for this function:

◆ GetRequiredVqMemSize()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
static constexpr auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::GetRequiredVqMemSize ( uint16_t  queue_count,
uint32_t  queue_size 
) -> std::pair<size_t, size_t>
inlinestaticconstexpr

获取多队列所需的总 DMA 内存大小

调用者应根据此值预分配页对齐、已清零的 DMA 内存。

Parameters
queue_count请求的队列数量
queue_size每个队列的描述符数量(必须为 2 的幂)
Returns
pair.first = 总字节数,pair.second = 对齐要求(字节)
See also
架构文档 §3

Definition at line 71 of file virtio_blk.hpp.

73 {
74 // 始终按 event_idx=true 分配,因为特性协商在分配之后
75 size_t per_queue =
76 VirtqueueT::CalcSize(static_cast<uint16_t>(queue_size), true);
77 return {per_queue * queue_count, 4096};
78 }

◆ GetStats()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::GetStats ( ) const -> VirtioStats
inline

获取性能监控统计数据

Returns
当前统计数据的快照
See also
架构文档 §3

Definition at line 474 of file virtio_blk.hpp.

474{ return stats_; }

◆ HandleInterrupt() [1/2]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::HandleInterrupt ( ) -> void
inline

中断处理(简化版,无回调)

仅确认设备中断并设置完成标志,供同步轮询使用。 不处理 Used Ring 和描述符回收。

Note
此方法可在中断上下文中安全调用(ISR-safe)
See also
virtio-v1.2#2.3 Notifications

Definition at line 300 of file virtio_blk.hpp.

300 {
301 uint32_t status = transport_.GetInterruptStatus();
302 if (status != 0) {
303 transport_.AckInterrupt(status);
304 }
306 request_completed_ = true;
307 cpu_io::Wmb();
308 }
uint64_t interrupts_handled
已处理的中断次数
Here is the call graph for this function:

◆ HandleInterrupt() [2/2]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
template<typename CompletionCallback >
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::HandleInterrupt ( CompletionCallback &&  on_complete) -> void
inline

中断处理(带完成回调)

在 ISR 或轮询循环中调用。确认设备中断,遍历 Used Ring 中已完成的请求, 对每个请求调用 on_complete 回调,释放描述符链和请求槽。

Template Parameters
CompletionCallback签名要求:void(UserData token, ErrorCode status)
  • token: 提交时传入的用户上下文指针
  • status: 设备返回的完成状态映射为 ErrorCode
Parameters
on_complete完成回调函数
See also
virtio-v1.2#2.7.14 Receiving Used Buffers From The Device

Definition at line 279 of file virtio_blk.hpp.

279 {
280 // 确认中断
281 uint32_t isr_status = transport_.GetInterruptStatus();
282 if (isr_status != 0) {
283 transport_.AckInterrupt(isr_status);
284 }
286
287 ProcessCompletions(static_cast<CompletionCallback&&>(on_complete));
289 }
auto ProcessCompletions(CompletionCallback &&on_complete) -> void
处理 Used Ring 中已完成的请求
auto UpdateUsedEvent() -> void
更新 avail->used_event 字段
Here is the call graph for this function:

◆ Kick()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::Kick ( uint16_t  queue_index) -> void
inline

批量触发硬件通知

通知设备 Available Ring 中有新的待处理请求。 调用者应在 EnqueueRead/EnqueueWrite 后调用此方法。

Parameters
queue_index队列索引(当前仅支持 0)
See also
virtio-v1.2#2.7.13 Supplying Buffers to The Device

Definition at line 240 of file virtio_blk.hpp.

240 {
241 if (queue_index != 0) {
242 return;
243 }
244 // 写屏障:确保 Available Ring 更新对设备可见
245 cpu_io::Wmb();
246
247 if (vq_.EventIdxEnabled()) {
248 auto* avail_event_ptr = vq_.UsedAvailEvent();
249 if (avail_event_ptr != nullptr) {
250 uint16_t avail_event = *avail_event_ptr;
251 uint16_t new_idx = vq_.AvailIdx();
252 if (VringNeedEvent(avail_event, new_idx, old_avail_idx_)) {
253 transport_.NotifyQueue(queue_index);
254 } else {
256 }
257 old_avail_idx_ = new_idx;
258 } else {
259 transport_.NotifyQueue(queue_index);
260 }
261 } else {
262 transport_.NotifyQueue(queue_index);
263 }
264 }
static auto VringNeedEvent(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx) -> bool
判断是否需要发送通知(处理 wrap-around)
uint64_t kicks_elided
借助 Event Index 省略的 Kick 次数
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MapBlkStatus()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
static auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::MapBlkStatus ( uint8_t  status) -> ErrorCode
inlinestaticprivate

将设备 BlkStatus 映射为 ErrorCode

Parameters
status设备返回的原始状态字节
Returns
对应的 ErrorCode

Definition at line 727 of file virtio_blk.hpp.

727 {
728 switch (status) {
729 case static_cast<uint8_t>(BlkStatus::kOk):
730 return ErrorCode::kSuccess;
731 case static_cast<uint8_t>(BlkStatus::kIoErr):
732 return ErrorCode::kIoError;
733 case static_cast<uint8_t>(BlkStatus::kUnsupp):
734 return ErrorCode::kNotSupported;
735 default:
737 }
738 }
ErrorCode
内核错误码
Definition expected.hpp:11
@ kIoError
IO 操作错误
@ kDeviceError
通用设备报告错误
@ kNotSupported
不支持的操作(通用,非设备特定)
@ kUnsupp
不支持的操作 (VIRTIO_BLK_S_UNSUPP)
@ kIoErr
IO 错误 (VIRTIO_BLK_S_IOERR)
@ kOk
操作成功 (VIRTIO_BLK_S_OK)
Here is the caller graph for this function:

◆ operator=() [1/2]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::operator= ( const VirtioBlk< TransportT, VirtqueueT > &  ) -> VirtioBlk &=delete
delete

◆ operator=() [2/2]

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::operator= ( VirtioBlk< TransportT, VirtqueueT > &&  other) -> VirtioBlk&
inlinenoexcept

Definition at line 493 of file virtio_blk.hpp.

493 {
494 if (this != &other) {
495 transport_ = std::move(other.transport_);
496 vq_ = std::move(other.vq_);
497 negotiated_features_ = other.negotiated_features_;
498 slot_dma_ = other.slot_dma_;
499 slots_ = other.slots_;
500 virt_to_phys_ = other.virt_to_phys_;
501 stats_ = other.stats_;
502 slot_bitmap_ = other.slot_bitmap_;
503 old_avail_idx_ = other.old_avail_idx_;
504 request_completed_ = other.request_completed_;
505 other.slots_ = nullptr;
506 other.slot_bitmap_ = 0;
507 }
508 return *this;
509 }

◆ ProcessCompletions()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
template<typename CompletionCallback >
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::ProcessCompletions ( CompletionCallback &&  on_complete) -> void
inlineprivate

处理 Used Ring 中已完成的请求

遍历 Used Ring,对每个已完成的请求:

  1. 查找对应的请求槽
  2. 读取设备返回的状态字节
  3. 调用回调函数
  4. 释放描述符链和请求槽
Template Parameters
CompletionCallbackvoid(UserData token, ErrorCode status)
Parameters
on_complete完成回调

Definition at line 644 of file virtio_blk.hpp.

644 {
645 cpu_io::Rmb();
646
647 while (vq_.HasUsed()) {
648 auto elem_result = vq_.PopUsed();
649 if (!elem_result) {
650 break;
651 }
652
653 auto elem = *elem_result;
654 auto head = static_cast<uint16_t>(elem.id);
655
656 uint16_t slot_idx = FindSlotByDescHead(head);
657 if (slot_idx < kMaxInflight) {
658 auto& slot = slots_[slot_idx];
659
660 cpu_io::Rmb();
661
662 ErrorCode ec = MapBlkStatus(slot.status);
663 on_complete(slot.token, ec);
664 stats_.bytes_transferred += elem.len;
665 FreeRequestSlot(slot_idx);
666 }
667
668 (void)vq_.FreeChain(head);
669 }
670 }
auto FindSlotByDescHead(uint16_t desc_head) const -> uint16_t
根据描述符链头索引查找请求槽
static auto MapBlkStatus(uint8_t status) -> ErrorCode
将设备 BlkStatus 映射为 ErrorCode
void Rmb()
Definition cpu_io.h:57
uint64_t bytes_transferred
已传输字节数
Here is the call graph for this function:
Here is the caller graph for this function:

◆ Read()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::Read ( uint64_t  sector,
uint8_t *  data 
) -> Expected<void>
inline

同步读取一个扇区

基于异步接口实现:EnqueueRead → Kick → 轮询 HandleInterrupt → 返回。

Parameters
sector起始扇区号(以 512 字节为单位)
data数据缓冲区(至少 kSectorSize 字节,必须位于 DMA 可访问内存)
Returns
成功或失败
Note
缓冲区在函数返回前不得释放或修改
See also
virtio-v1.2#5.2.6 Device Operation

Definition at line 323 of file virtio_blk.hpp.

323 {
324 if (data == nullptr) {
325 return std::unexpected(Error{ErrorCode::kInvalidArgument});
326 }
327 IoVec data_iov{virt_to_phys_(reinterpret_cast<uintptr_t>(data)),
329 return SubmitSyncRequest(ReqType::kIn, sector, &data_iov, 1);
330 }
auto SubmitSyncRequest(ReqType type, uint64_t sector, const IoVec *buffers, size_t buffer_count) -> Expected< void >
同步提交请求的内部实现
constexpr size_t kSectorSize
标准扇区大小(字节)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReadConfig()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::ReadConfig ( ) const -> BlkConfig
inline

读取块设备配置空间

读取设备的配置信息,包括容量、几何信息、拓扑信息等。 配置空间的可用字段取决于协商的特性位。

Returns
块设备配置结构
See also
virtio-v1.2#5.2.4 Device configuration layout

Definition at line 365 of file virtio_blk.hpp.

365 {
366 BlkConfig config{};
367
368 config.capacity = transport_.ReadConfigU64(
369 static_cast<uint32_t>(BlkConfigOffset::kCapacity));
370 config.size_max = transport_.ReadConfigU32(
371 static_cast<uint32_t>(BlkConfigOffset::kSizeMax));
372 config.seg_max = transport_.ReadConfigU32(
373 static_cast<uint32_t>(BlkConfigOffset::kSegMax));
374
376 static_cast<uint64_t>(BlkFeatureBit::kGeometry)) != 0) {
377 config.geometry.cylinders = transport_.ReadConfigU16(
378 static_cast<uint32_t>(BlkConfigOffset::kGeometryCylinders));
379 config.geometry.heads = transport_.ReadConfigU8(
380 static_cast<uint32_t>(BlkConfigOffset::kGeometryHeads));
381 config.geometry.sectors = transport_.ReadConfigU8(
382 static_cast<uint32_t>(BlkConfigOffset::kGeometrySectors));
383 }
384
386 static_cast<uint64_t>(BlkFeatureBit::kBlkSize)) != 0) {
387 config.blk_size = transport_.ReadConfigU32(
388 static_cast<uint32_t>(BlkConfigOffset::kBlkSize));
389 }
390
392 static_cast<uint64_t>(BlkFeatureBit::kTopology)) != 0) {
393 config.topology.physical_block_exp = transport_.ReadConfigU8(
394 static_cast<uint32_t>(BlkConfigOffset::kTopologyPhysBlockExp));
395 config.topology.alignment_offset = transport_.ReadConfigU8(
396 static_cast<uint32_t>(BlkConfigOffset::kTopologyAlignOffset));
397 config.topology.min_io_size = transport_.ReadConfigU16(
398 static_cast<uint32_t>(BlkConfigOffset::kTopologyMinIoSize));
399 config.topology.opt_io_size = transport_.ReadConfigU32(
400 static_cast<uint32_t>(BlkConfigOffset::kTopologyOptIoSize));
401 }
402
404 static_cast<uint64_t>(BlkFeatureBit::kConfigWce)) != 0) {
405 config.writeback = transport_.ReadConfigU8(
406 static_cast<uint32_t>(BlkConfigOffset::kWriteback));
407 }
408
410 static_cast<uint64_t>(BlkFeatureBit::kDiscard)) != 0) {
411 config.max_discard_sectors = transport_.ReadConfigU32(
412 static_cast<uint32_t>(BlkConfigOffset::kMaxDiscardSectors));
413 config.max_discard_seg = transport_.ReadConfigU32(
414 static_cast<uint32_t>(BlkConfigOffset::kMaxDiscardSeg));
415 config.discard_sector_alignment = transport_.ReadConfigU32(
416 static_cast<uint32_t>(BlkConfigOffset::kDiscardSectorAlignment));
417 }
418
420 static_cast<uint64_t>(BlkFeatureBit::kWriteZeroes)) != 0) {
421 config.max_write_zeroes_sectors = transport_.ReadConfigU32(
422 static_cast<uint32_t>(BlkConfigOffset::kMaxWriteZeroesSectors));
423 config.max_write_zeroes_seg = transport_.ReadConfigU32(
424 static_cast<uint32_t>(BlkConfigOffset::kMaxWriteZeroesSeg));
425 config.write_zeroes_may_unmap = transport_.ReadConfigU8(
426 static_cast<uint32_t>(BlkConfigOffset::kWriteZeroesMayUnmap));
427 }
428
430 static_cast<uint64_t>(BlkFeatureBit::kSecureErase)) != 0) {
431 config.max_secure_erase_sectors = transport_.ReadConfigU32(
432 static_cast<uint32_t>(BlkConfigOffset::kMaxSecureEraseSectors));
433 config.max_secure_erase_seg = transport_.ReadConfigU32(
434 static_cast<uint32_t>(BlkConfigOffset::kMaxSecureEraseSeg));
435 config.secure_erase_sector_alignment = transport_.ReadConfigU32(
436 static_cast<uint32_t>(BlkConfigOffset::kSecureEraseSectorAlignment));
437 }
438
439 if ((negotiated_features_ & static_cast<uint64_t>(BlkFeatureBit::kMq)) !=
440 0) {
441 config.num_queues = transport_.ReadConfigU16(
442 static_cast<uint32_t>(BlkConfigOffset::kNumQueues));
443 }
444
445 return config;
446 }
@ kWriteZeroes
设备支持 write zeroes 命令 (VIRTIO_BLK_F_WRITE_ZEROES)
@ kDiscard
设备支持 discard 命令 (VIRTIO_BLK_F_DISCARD)
@ kTopology
设备配置空间中 topology 字段有效 (VIRTIO_BLK_F_TOPOLOGY)
@ kMq
设备支持多队列 (VIRTIO_BLK_F_MQ)
@ kConfigWce
设备可在回写和直写缓存模式间切换 (VIRTIO_BLK_F_CONFIG_WCE)
@ kBlkSize
设备配置空间中 blk_size 字段有效 (VIRTIO_BLK_F_BLK_SIZE)
@ kSecureErase
设备支持 secure erase 命令 (VIRTIO_BLK_F_SECURE_ERASE)
@ kGeometry
设备配置空间中 geometry 字段有效 (VIRTIO_BLK_F_GEOMETRY)

◆ SubmitSyncRequest()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::SubmitSyncRequest ( ReqType  type,
uint64_t  sector,
const IoVec buffers,
size_t  buffer_count 
) -> Expected<void>
inlineprivate

同步提交请求的内部实现

Read()/Write() 的共享实现:入队 → Kick → 轮询等待 → 处理完成 → 返回。 轮询上限固定为 100000000 次迭代。

Parameters
type请求类型(kIn/kOut)
sector起始扇区号
buffers数据缓冲区 IoVec 数组
buffer_count缓冲区数量
Returns
成功或失败

Definition at line 788 of file virtio_blk.hpp.

790 {
791 auto enq = DoEnqueue(type, 0, sector, buffers, buffer_count, nullptr);
792 if (!enq) {
793 return std::unexpected(enq.error());
794 }
795
796 Kick(0);
797
798 uint32_t spin_limit = 100000000U;
799
800 for (uint32_t i = 0; i < spin_limit; ++i) {
801 cpu_io::Rmb();
802 if (vq_.HasUsed()) {
803 break;
804 }
805 }
806
807 if (!vq_.HasUsed()) {
808 klog::Warn("Sync request timeout: sector={}", sector);
809 return std::unexpected(Error{ErrorCode::kTimeout});
810 }
811
813 bool done = false;
814 ProcessCompletions([&done, &result](UserData, ErrorCode status) {
815 done = true;
816 result = status;
817 });
819
820 if (!done) {
821 return std::unexpected(Error{ErrorCode::kTimeout});
822 }
823 if (result != ErrorCode::kSuccess) {
824 return std::unexpected(Error{result});
825 }
826 return {};
827 }
auto Kick(uint16_t queue_index) -> void
批量触发硬件通知
void * UserData
异步 IO 回调中使用的用户自定义上下文指针类型
@ kTimeout
操作超时
auto Warn(etl::format_string< Args... > fmt, Args &&... args) -> void
以 WARN 级别记录日志
Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdateUsedEvent()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::UpdateUsedEvent ( ) -> void
inlineprivate

更新 avail->used_event 字段

在处理完 Used Ring 后调用,告知设备下次在此索引之后再发送中断。 仅在协商了 VIRTIO_F_EVENT_IDX 时生效。

See also
virtio-v1.2#2.7.10 Available Buffer Notification Suppression

Definition at line 766 of file virtio_blk.hpp.

766 {
767 if (vq_.EventIdxEnabled()) {
768 auto* used_event_ptr = vq_.AvailUsedEvent();
769 if (used_event_ptr != nullptr) {
770 *used_event_ptr = vq_.LastUsedIdx();
771 cpu_io::Wmb();
772 }
773 }
774 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ VringNeedEvent()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
static auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::VringNeedEvent ( uint16_t  event_idx,
uint16_t  new_idx,
uint16_t  old_idx 
) -> bool
inlinestaticprivate

判断是否需要发送通知(处理 wrap-around)

基于 virtio 规范中的 vring_need_event 算法:检查 event_idx 是否落在 (old, new] 区间内(含 uint16_t 回绕处理)。

Parameters
event_idx设备/驱动期望的通知阈值
new_idx当前索引
old_idx上次通知时的索引
Returns
true 表示需要发送通知
See also
virtio-v1.2#2.7.10 Available Buffer Notification Suppression

Definition at line 752 of file virtio_blk.hpp.

753 {
754 return static_cast<uint16_t>(new_idx - event_idx - 1) <
755 static_cast<uint16_t>(new_idx - old_idx);
756 }
Here is the caller graph for this function:

◆ Write()

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
auto virtio::blk::VirtioBlk< TransportT, VirtqueueT >::Write ( uint64_t  sector,
const uint8_t *  data 
) -> Expected<void>
inline

同步写入一个扇区

基于异步接口实现:EnqueueWrite → Kick → 轮询 HandleInterrupt → 返回。

Parameters
sector起始扇区号(以 512 字节为单位)
data数据缓冲区(至少 kSectorSize 字节,必须位于 DMA 可访问内存)
Returns
成功或失败
Note
如果设备协商了 VIRTIO_BLK_F_RO,写请求将返回错误
See also
virtio-v1.2#5.2.6 Device Operation

Definition at line 343 of file virtio_blk.hpp.

344 {
345 if (data == nullptr) {
346 return std::unexpected(Error{ErrorCode::kInvalidArgument});
347 }
348 IoVec data_iov{
349 virt_to_phys_(reinterpret_cast<uintptr_t>(const_cast<uint8_t*>(data))),
351 return SubmitSyncRequest(ReqType::kOut, sector, &data_iov, 1);
352 }
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ kMaxInflight

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
constexpr uint16_t virtio::blk::VirtioBlk< TransportT, VirtqueueT >::kMaxInflight = 64
staticconstexpr

每个设备的最大并发(in-flight)请求数

Definition at line 56 of file virtio_blk.hpp.

◆ kMaxSgElements

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
constexpr size_t virtio::blk::VirtioBlk< TransportT, VirtqueueT >::kMaxSgElements = 18
staticconstexpr

每个 Scatter-Gather 请求的最大 IoVec 数量(含请求头和状态字节)

Definition at line 59 of file virtio_blk.hpp.

◆ negotiated_features_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
uint64_t virtio::blk::VirtioBlk< TransportT, VirtqueueT >::negotiated_features_ {0}
private

协商后的特性位掩码

Definition at line 833 of file virtio_blk.hpp.

833{0};

◆ old_avail_idx_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
uint16_t virtio::blk::VirtioBlk< TransportT, VirtqueueT >::old_avail_idx_ {0}
private

上次 Kick 时的 avail idx(用于 Event Index 通知抑制)

Definition at line 845 of file virtio_blk.hpp.

845{0};

◆ request_completed_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
volatile bool virtio::blk::VirtioBlk< TransportT, VirtqueueT >::request_completed_ {false}
private

请求完成标志(由简化版 HandleInterrupt 在中断上下文中设置)

Definition at line 847 of file virtio_blk.hpp.

847{false};

◆ slot_bitmap_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
uint64_t virtio::blk::VirtioBlk< TransportT, VirtqueueT >::slot_bitmap_ {}
private

请求槽占用位图(bit i = 1 表示 slots_[i] 被占用)

Definition at line 843 of file virtio_blk.hpp.

843{};

◆ slot_dma_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
DmaRegion virtio::blk::VirtioBlk< TransportT, VirtqueueT >::slot_dma_ {}
private

DMA region backing the request slot pool.

Definition at line 835 of file virtio_blk.hpp.

835{};

◆ slots_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
RequestSlot* virtio::blk::VirtioBlk< TransportT, VirtqueueT >::slots_ {nullptr}
private

Pointer to request slot array (lives in slot_dma_ memory)

Definition at line 837 of file virtio_blk.hpp.

837{nullptr};

◆ stats_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
VirtioStats virtio::blk::VirtioBlk< TransportT, VirtqueueT >::stats_
private

性能统计数据

Definition at line 841 of file virtio_blk.hpp.

◆ transport_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
TransportT virtio::blk::VirtioBlk< TransportT, VirtqueueT >::transport_
private

传输层实例

Definition at line 829 of file virtio_blk.hpp.

◆ virt_to_phys_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
VirtToPhysFunc virtio::blk::VirtioBlk< TransportT, VirtqueueT >::virt_to_phys_ {IdentityVirtToPhys}
private

Address translation callback.

Definition at line 839 of file virtio_blk.hpp.

auto IdentityVirtToPhys(uintptr_t virt) -> uintptr_t
恒等映射:物理地址 == 虚拟地址(早期启动 / 无 MMU 时的默认实现)
Definition io_buffer.hpp:25

◆ vq_

template<typename TransportT = MmioTransport, typename VirtqueueT = SplitVirtqueue>
VirtqueueT virtio::blk::VirtioBlk< TransportT, VirtqueueT >::vq_
private

Virtqueue 实例(当前支持单队列)

Definition at line 831 of file virtio_blk.hpp.


The documentation for this class was generated from the following file: