SimpleKernel 1.17.0
Loading...
Searching...
No Matches
mmio.hpp
Go to the documentation of this file.
1
5#pragma once
6
7#include <utility>
8
9#include "expected.hpp"
10#include "kernel_log.hpp"
11#include "mmio_accessor.hpp"
13
14namespace virtio {
15
20enum class InterruptStatus : uint32_t {
22 kUsedBuffer = 0x01,
24 kConfigChange = 0x02,
25};
26
31static constexpr uint32_t kMmioMagicValue = 0x74726976;
32
37static constexpr uint32_t kMmioVersionModern = 0x02;
38
61class MmioTransport final : public Transport {
62 public:
67 enum class MmioReg : size_t {
68 kMagicValue = 0x000,
69 kVersion = 0x004,
70 kDeviceId = 0x008,
71 kVendorId = 0x00C,
72 kDeviceFeatures = 0x010,
73 kDeviceFeaturesSel = 0x014,
74 // 0x018 ~ 0x01F: reserved
75 kDriverFeatures = 0x020,
76 kDriverFeaturesSel = 0x024,
77 // 0x028 ~ 0x02F: reserved
78 kQueueSel = 0x030,
79 kQueueNumMax = 0x034,
80 kQueueNum = 0x038,
81 // 0x03C ~ 0x03F: reserved
82 // 0x040 ~ 0x043: reserved
83 kQueueReady = 0x044,
84 // 0x048 ~ 0x04F: reserved
85 kQueueNotify = 0x050,
86 // 0x054 ~ 0x05F: reserved
87 kInterruptStatus = 0x060,
88 kInterruptAck = 0x064,
89 // 0x068 ~ 0x06F: reserved
90 kStatus = 0x070,
91 // 0x074 ~ 0x07F: reserved
92 kQueueDescLow = 0x080,
93 kQueueDescHigh = 0x084,
94 // 0x088 ~ 0x08F: reserved
95 kQueueDriverLow = 0x090,
96 kQueueDriverHigh = 0x094,
97 // 0x098 ~ 0x09F: reserved
98 kQueueDeviceLow = 0x0A0,
99 kQueueDeviceHigh = 0x0A4,
100 // 0x0A8 ~ 0x0AB: reserved
101 kShmSel = 0x0AC,
102 kShmLenLow = 0x0B0,
103 kShmLenHigh = 0x0B4,
104 kShmBaseLow = 0x0B8,
105 kShmBaseHigh = 0x0BC,
106 kQueueReset = 0x0C0,
107 // 0x0C4 ~ 0x0FB: reserved
108 kConfigGeneration = 0x0FC,
109 kConfig = 0x100,
110 };
111
126 explicit MmioTransport(uint64_t base)
127 : mmio_(base), is_valid_(false), device_id_(0), vendor_id_(0) {
128 if (base == 0) {
129 return;
130 }
131
132 auto magic = mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kMagicValue));
133 if (magic != kMmioMagicValue) {
134 return;
135 }
136
137 auto version = mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kVersion));
138 if (version != kMmioVersionModern) {
139 return;
140 }
141
142 device_id_ = mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kDeviceId));
143 if (device_id_ == 0) {
144 return;
145 }
146
147 vendor_id_ = mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kVendorId));
148 this->Reset();
149 is_valid_ = true;
150 }
151
155 [[nodiscard]] auto IsValid() const -> bool { return is_valid_; }
156
159 MmioTransport(MmioTransport&& other) noexcept
160 : Transport(std::move(other)),
161 mmio_(other.mmio_),
162 is_valid_(other.is_valid_),
163 device_id_(other.device_id_),
164 vendor_id_(other.vendor_id_) {
165 other.is_valid_ = false;
166 }
167 auto operator=(MmioTransport&&) noexcept -> MmioTransport& = delete;
168 MmioTransport(const MmioTransport&) = delete;
169 auto operator=(const MmioTransport&) -> MmioTransport& = delete;
171
172 [[nodiscard]] auto GetDeviceId() const -> uint32_t { return device_id_; }
173
174 [[nodiscard]] auto GetVendorId() const -> uint32_t { return vendor_id_; }
175
176 [[nodiscard]] auto GetStatus() const -> uint32_t {
177 return mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kStatus));
178 }
179
180 auto SetStatus(uint32_t status) -> void {
181 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kStatus), status);
182 }
183
193 [[nodiscard]] auto GetDeviceFeatures() -> uint64_t {
194 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kDeviceFeaturesSel), 0);
195 uint64_t lo =
196 mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kDeviceFeatures));
197
198 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kDeviceFeaturesSel), 1);
199 uint64_t hi =
200 mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kDeviceFeatures));
201
202 return (hi << 32) | lo;
203 }
204
211 auto SetDriverFeatures(uint64_t features) -> void {
212 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kDriverFeaturesSel), 0);
213 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kDriverFeatures),
214 static_cast<uint32_t>(features));
215
216 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kDriverFeaturesSel), 1);
217 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kDriverFeatures),
218 static_cast<uint32_t>(features >> 32));
219 }
220
230 [[nodiscard]] auto GetQueueNumMax(uint32_t queue_idx) -> uint32_t {
231 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
232 return mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kQueueNumMax));
233 }
234
235 auto SetQueueNum(uint32_t queue_idx, uint32_t num) -> void {
236 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
237 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueNum), num);
238 }
239
246 auto SetQueueDesc(uint32_t queue_idx, uint64_t addr) -> void {
247 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
248 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueDescLow),
249 static_cast<uint32_t>(addr));
250 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueDescHigh),
251 static_cast<uint32_t>(addr >> 32));
252 }
253
260 auto SetQueueAvail(uint32_t queue_idx, uint64_t addr) -> void {
261 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
262 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueDriverLow),
263 static_cast<uint32_t>(addr));
264 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueDriverHigh),
265 static_cast<uint32_t>(addr >> 32));
266 }
267
274 auto SetQueueUsed(uint32_t queue_idx, uint64_t addr) -> void {
275 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
276 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueDeviceLow),
277 static_cast<uint32_t>(addr));
278 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueDeviceHigh),
279 static_cast<uint32_t>(addr >> 32));
280 }
281
282 [[nodiscard]] auto GetQueueReady(uint32_t queue_idx) -> bool {
283 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
284 return mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kQueueReady)) != 0;
285 }
286
287 auto SetQueueReady(uint32_t queue_idx, bool ready) -> void {
288 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueSel), queue_idx);
289 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueReady),
290 ready ? 1 : 0);
291 }
292
294 auto NotifyQueue(uint32_t queue_idx) -> void {
295 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kQueueNotify), queue_idx);
296 }
297
298 [[nodiscard]] auto GetInterruptStatus() const -> uint32_t {
299 return mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kInterruptStatus));
300 }
301
302 auto AckInterrupt(uint32_t ack_bits) -> void {
303 mmio_.Write<uint32_t>(std::to_underlying(MmioReg::kInterruptAck), ack_bits);
304 }
305
312 [[nodiscard]] auto ReadConfigU8(uint32_t offset) const -> uint8_t {
313 return mmio_.Read<uint8_t>(std::to_underlying(MmioReg::kConfig) + offset);
314 }
315
321 [[nodiscard]] auto ReadConfigU16(uint32_t offset) const -> uint16_t {
322 return mmio_.Read<uint16_t>(std::to_underlying(MmioReg::kConfig) + offset);
323 }
324
330 [[nodiscard]] auto ReadConfigU32(uint32_t offset) const -> uint32_t {
331 return mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kConfig) + offset);
332 }
333
348 [[nodiscard]] auto ReadConfigU64(uint32_t offset) const -> uint64_t {
349 uint32_t gen1;
350 uint32_t gen2;
351 uint64_t value;
352
353 static constexpr uint32_t kMaxConfigRetries = 1000;
354 uint32_t retries = 0;
355 do {
356 gen1 = GetConfigGeneration();
357
358 auto* ptr = reinterpret_cast<volatile uint32_t*>(
359 mmio_.base + std::to_underlying(MmioReg::kConfig) + offset);
360 uint64_t lo = ptr[0];
361 uint64_t hi = ptr[1];
362 value = (hi << 32) | lo;
363
364 gen2 = GetConfigGeneration();
365 } while (gen1 != gen2 && ++retries < kMaxConfigRetries);
366
367 return value;
368 }
369
370 [[nodiscard]] auto GetConfigGeneration() const -> uint32_t {
371 return mmio_.Read<uint32_t>(std::to_underlying(MmioReg::kConfigGeneration));
372 }
373
374 private:
377
380
382 uint32_t device_id_;
383
385 uint32_t vendor_id_;
386};
387
388} // namespace virtio
Virtio MMIO 传输层
Definition mmio.hpp:61
uint32_t device_id_
设备 ID(缓存以避免重复读取)
Definition mmio.hpp:382
MmioReg
MMIO 寄存器偏移量
Definition mmio.hpp:67
auto AckInterrupt(uint32_t ack_bits) -> void
Definition mmio.hpp:302
auto GetInterruptStatus() const -> uint32_t
Definition mmio.hpp:298
auto SetDriverFeatures(uint64_t features) -> void
写入 64 位驱动特性
Definition mmio.hpp:211
auto GetStatus() const -> uint32_t
Definition mmio.hpp:176
bool is_valid_
设备是否成功初始化
Definition mmio.hpp:379
uint32_t vendor_id_
供应商 ID(缓存以避免重复读取)
Definition mmio.hpp:385
MmioTransport(uint64_t base)
构造函数
Definition mmio.hpp:126
MmioAccessor mmio_
MMIO 寄存器访问器
Definition mmio.hpp:376
auto GetDeviceFeatures() -> uint64_t
读取 64 位设备特性
Definition mmio.hpp:193
auto GetDeviceId() const -> uint32_t
Definition mmio.hpp:172
auto ReadConfigU64(uint32_t offset) const -> uint64_t
读取配置空间 64 位值
Definition mmio.hpp:348
auto SetQueueDesc(uint32_t queue_idx, uint64_t addr) -> void
设置描述符表物理地址
Definition mmio.hpp:246
auto GetQueueReady(uint32_t queue_idx) -> bool
Definition mmio.hpp:282
auto GetConfigGeneration() const -> uint32_t
Definition mmio.hpp:370
auto ReadConfigU8(uint32_t offset) const -> uint8_t
读取配置空间 8 位值
Definition mmio.hpp:312
auto operator=(MmioTransport &&) noexcept -> MmioTransport &=delete
auto GetVendorId() const -> uint32_t
Definition mmio.hpp:174
auto GetQueueNumMax(uint32_t queue_idx) -> uint32_t
获取队列最大容量
Definition mmio.hpp:230
auto ReadConfigU32(uint32_t offset) const -> uint32_t
读取配置空间 32 位值
Definition mmio.hpp:330
auto IsValid() const -> bool
检查设备是否成功初始化
Definition mmio.hpp:155
auto SetQueueReady(uint32_t queue_idx, bool ready) -> void
Definition mmio.hpp:287
auto NotifyQueue(uint32_t queue_idx) -> void
通知设备有新的可用缓冲区
Definition mmio.hpp:294
auto SetQueueNum(uint32_t queue_idx, uint32_t num) -> void
Definition mmio.hpp:235
auto SetQueueAvail(uint32_t queue_idx, uint64_t addr) -> void
设置 Available Ring 物理地址
Definition mmio.hpp:260
auto SetStatus(uint32_t status) -> void
Definition mmio.hpp:180
MmioTransport(MmioTransport &&other) noexcept
Definition mmio.hpp:159
auto SetQueueUsed(uint32_t queue_idx, uint64_t addr) -> void
设置 Used Ring 物理地址
Definition mmio.hpp:274
auto ReadConfigU16(uint32_t offset) const -> uint16_t
读取配置空间 16 位值
Definition mmio.hpp:321
Virtio 传输层基类(零虚表开销,C++23 Deducing this)
Definition transport.hpp:83
auto Reset(this auto &&self) -> void
重置设备
Transport()=default
Definition defs.h:9
InterruptStatus
MMIO 中断状态位
Definition mmio.hpp:20
@ kConfigChange
设备配置已更改 Configuration Change Notification
@ kUsedBuffer
设备在至少一个活动虚拟队列中使用了缓冲区 Used Buffer Notification
static constexpr uint32_t kMmioMagicValue
MMIO 魔数: little-endian "virt" = 0x74726976.
Definition mmio.hpp:31
static constexpr uint32_t kMmioVersionModern
Modern VirtIO MMIO 版本号(VirtIO 1.0+)
Definition mmio.hpp:37
通用 MMIO 寄存器访问器
auto Write(size_t offset, T val) const -> void
Write to MMIO register.
auto Read(size_t offset) const -> T
Read from MMIO register.