SimpleKernel 1.17.0
Loading...
Searching...
No Matches
virtio_driver.cpp
Go to the documentation of this file.
1
6
7#include <etl/io_port.h>
8
9#include <utility>
10
11#include "expected.hpp"
12#include "io_buffer.hpp"
13#include "kernel_log.hpp"
15
16auto VirtioDriver::MatchStatic([[maybe_unused]] DeviceNode& node) -> bool {
17 return node.mmio_base != 0 && node.mmio_size != 0;
18}
19
21 if (node.mmio_size == 0) {
22 klog::Err("VirtioDriver: FDT reg property missing size for node '{}'",
23 node.name);
24 return std::unexpected(Error(ErrorCode::kInvalidArgument));
25 }
26 auto ctx = mmio_helper::Prepare(node, node.mmio_size);
27 if (!ctx) {
28 return std::unexpected(ctx.error());
29 }
30
31 etl::io_port_ro<uint32_t> magic_reg{reinterpret_cast<void*>(ctx->base)};
32 if (magic_reg.read() != virtio::kMmioMagicValue) {
33 return std::unexpected(Error(ErrorCode::kNotSupported));
34 }
35
36 // 读取 device_id
37 etl::io_port_ro<uint32_t> device_id_reg{reinterpret_cast<void*>(
38 ctx->base +
40 const auto device_id = static_cast<DeviceId>(device_id_reg.read());
41
42 switch (device_id) {
43 case DeviceId::kBlock: {
44 if (blk_device_count_ >= kMaxBlkDevices) {
46 "VirtioDriver: blk device pool full, device at {:#x} skipped",
47 ctx->base);
48 return std::unexpected(Error(ErrorCode::kOutOfMemory));
49 }
50 const size_t idx = blk_device_count_;
51
52 // 分配 DMA buffer
53 dma_buffers_[idx] = kstd::make_unique<IoBuffer>(kMinDmaBufferSize);
54 if (!dma_buffers_[idx] || !dma_buffers_[idx]->IsValid() ||
55 dma_buffers_[idx]->GetBuffer().size() < kMinDmaBufferSize) {
56 klog::Err("VirtioDriver: failed to allocate DMA buffer at {:#x}",
57 ctx->base);
58 return std::unexpected(Error(ErrorCode::kOutOfMemory));
59 }
60
61 // Allocate slot DMA buffer
62 auto [slot_size, slot_align] =
64 slot_buffers_[idx] = kstd::make_unique<IoBuffer>(slot_size, slot_align);
65 if (!slot_buffers_[idx] || !slot_buffers_[idx]->IsValid()) {
66 klog::Err("VirtioDriver: failed to allocate slot DMA buffer at {:#x}",
67 ctx->base);
68 dma_buffers_[idx].reset();
69 return std::unexpected(Error(ErrorCode::kOutOfMemory));
70 }
71
72 uint64_t extra_features =
73 static_cast<uint64_t>(virtio::blk::BlkFeatureBit::kSegMax) |
74 static_cast<uint64_t>(virtio::blk::BlkFeatureBit::kSizeMax) |
75 static_cast<uint64_t>(virtio::blk::BlkFeatureBit::kBlkSize) |
76 static_cast<uint64_t>(virtio::blk::BlkFeatureBit::kFlush) |
77 static_cast<uint64_t>(virtio::blk::BlkFeatureBit::kGeometry);
78
79 auto vq_dma = dma_buffers_[idx]->ToDmaRegion();
80 auto slot_dma = slot_buffers_[idx]->ToDmaRegion();
81
83 ctx->base, vq_dma, slot_dma, IdentityVirtToPhys, kDefaultQueueCount,
84 kDefaultQueueSize, extra_features);
85 if (!result.has_value()) {
86 klog::Err("VirtioDriver: VirtioBlk Create failed at {:#x}", ctx->base);
87 dma_buffers_[idx].reset();
88 slot_buffers_[idx].reset();
89 return std::unexpected(Error(result.error().code));
90 }
91
92 blk_devices_[idx].emplace(std::move(*result));
93 node.type = DeviceType::kBlock;
94 irqs_[idx] = node.irq;
95
96 // Register adapter in pool and expose via DeviceNode.
97 if (blk_adapter_count_ < kMaxBlkDevices) {
98 const auto adapter_idx = static_cast<uint32_t>(blk_adapter_count_);
99 blk_adapters_[blk_adapter_count_].emplace(&blk_devices_[idx].value(),
100 adapter_idx);
101 node.block_device = &blk_adapters_[blk_adapter_count_].value();
102 ++blk_adapter_count_;
103 } else {
105 "VirtioDriver: blk adapter pool full, device at {:#x} skipped",
106 ctx->base);
107 }
108
109 ++blk_device_count_;
111 "VirtioDriver: block device at {:#x}, capacity={} sectors, irq={}",
112 ctx->base, blk_devices_[idx].value().GetCapacity(), irqs_[idx]);
113 return {};
114 }
115
116 default:
117 return std::unexpected(Error(ErrorCode::kNotSupported));
118 }
119}
DeviceId
VirtIO 设备类型枚举(来自 VirtIO 1.2 规范)
auto Probe(DeviceNode &node) -> Expected< void >
初始化 VirtIO 设备
static auto MatchStatic(DeviceNode &node) -> bool
硬件检测:验证 VirtIO magic number
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 constexpr auto GetRequiredSlotMemSize() -> std::pair< size_t, size_t >
计算 RequestSlot DMA 内存所需字节数
@ kBlock
块设备(磁盘等)
@ kInvalidArgument
@ kNotSupported
不支持的操作(通用,非设备特定)
std::expected< T, Error > Expected
std::expected 别名模板
Definition expected.hpp:365
auto IdentityVirtToPhys(uintptr_t virt) -> uintptr_t
恒等映射:物理地址 == 虚拟地址(早期启动 / 无 MMU 时的默认实现)
Definition io_buffer.hpp:25
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
auto Warn(etl::format_string< Args... > fmt, Args &&... args) -> void
以 WARN 级别记录日志
auto Prepare(const DeviceNode &node, size_t default_size) -> Expected< ProbeContext >
从节点提取 MMIO base/size 并通过 VirtualMemory 映射该区域。
@ kSegMax
设备配置空间中 seg_max 字段有效 (VIRTIO_BLK_F_SEG_MAX)
@ kSizeMax
设备配置空间中 size_max 字段有效 (VIRTIO_BLK_F_SIZE_MAX)
@ kBlkSize
设备配置空间中 blk_size 字段有效 (VIRTIO_BLK_F_BLK_SIZE)
@ kFlush
设备支持缓存刷新命令 (VIRTIO_BLK_F_FLUSH)
@ kGeometry
设备配置空间中 geometry 字段有效 (VIRTIO_BLK_F_GEOMETRY)
static constexpr uint32_t kMmioMagicValue
MMIO 魔数: little-endian "virt" = 0x74726976.
Definition mmio.hpp:31
单个设备的硬件资源描述。
错误类型,用于 std::expected
Definition expected.hpp:343