* @brief 计算给定队列大小所需的 DMA 内存字节数 * * @param queue_size 队列大小(必须为 2 的幂) * @param event_idx 是否启用 VIRTIO_F_EVENT_IDX 特性 * @param used_align Used Ring 的对齐要求 * @return 所需的 DMA 内存字节数 * @see virtio-v1.2#2.6 Split Virtqueues */
| 201 | * @see virtio-v1.2#2.6 Split Virtqueues |
| 202 | */ |
| 203 | [[nodiscard]] static constexpr auto CalcSize(uint16_t queue_size, |
| 204 | bool event_idx = true, |
| 205 | size_t used_align = Used::kAlign) |
| 206 | -> size_t { |
| 207 | // Descriptor Table: sizeof(Desc) * queue_size |
| 208 | size_t desc_total = static_cast<size_t>(sizeof(Desc)) * queue_size; |
| 209 | |
| 210 | // Available Ring: flags(2) + idx(2) + ring[N](2*N) + used_event(2, 可选) |
| 211 | size_t avail_total = sizeof(uint16_t) * (2 + queue_size); |
| 212 | if (event_idx) { |
| 213 | avail_total += sizeof(uint16_t); |
| 214 | } |
| 215 | |
| 216 | // Used Ring: flags(2) + idx(2) + ring[N](sizeof(UsedElem)*N) + |
| 217 | // avail_event(2, 可选) |
| 218 | size_t used_total = sizeof(uint16_t) * 2 + sizeof(UsedElem) * queue_size; |
| 219 | if (event_idx) { |
| 220 | used_total += sizeof(uint16_t); |
| 221 | } |
| 222 | |
| 223 | // 按对齐要求排列 |
| 224 | size_t avail_off = AlignUp(desc_total, Avail::kAlign); |
| 225 | size_t used_off = AlignUp(avail_off + avail_total, used_align); |
| 226 | |
| 227 | return used_off + used_total; |
| 228 | } |
| 229 | |
| 230 | /** |
| 231 | * @brief 从预分配的 DMA 缓冲区构造 SplitVirtqueue |