L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
virtqueue
1// vi:set ft=cpp: -*- Mode: C++ -*-
2/* SPDX-License-Identifier: MIT */
3/*
4 * (c) 2014 Alexander Warg <warg@os.inf.tu-dresden.de>
5 */
6
7#include <l4/re/util/debug>
8#include <l4/sys/types.h>
9#include <l4/sys/err.h>
10#include <l4/cxx/bitfield>
11#include <l4/cxx/exceptions>
12#include <cstdint>
13
14#pragma once
15
16namespace L4virtio {
17
18#if defined(__ARM_ARCH) && __ARM_ARCH == 7
19static inline void wmb() { asm volatile ("dmb ishst" : : : "memory"); }
20static inline void rmb() { asm volatile ("dmb ish" : : : "memory"); }
21#elif defined(__ARM_ARCH) && __ARM_ARCH >= 8
22static inline void wmb() { asm volatile ("dmb ishst" : : : "memory"); }
23static inline void rmb() { asm volatile ("dmb ishld" : : : "memory"); }
24#elif defined(__mips__)
25static inline void wmb() { asm volatile ("sync" : : : "memory"); }
26static inline void rmb() { asm volatile ("sync" : : : "memory"); }
27#elif defined(__amd64__) || defined(__i386__) || defined(__i686__)
28static inline void wmb() { asm volatile ("sfence" : : : "memory"); }
29static inline void rmb() { asm volatile ("lfence" : : : "memory"); }
30#elif defined(__riscv)
31static inline void wmb() { asm volatile ("fence ow, ow" : : : "memory"); }
32static inline void rmb() { asm volatile ("fence ir, ir" : : : "memory"); }
33#else
34#warning Missing proper memory write barrier
35static inline void wmb() { asm volatile ("" : : : "memory"); }
36static inline void rmb() { asm volatile ("" : : : "memory"); }
37#endif
38
39
46template< typename T >
47class Ptr
48{
49public:
52
53 Ptr() = default;
54
56 Ptr(Invalid_type) : _p(~0ULL) {}
57
59 explicit Ptr(l4_uint64_t vm_addr) : _p(vm_addr) {}
60
62 l4_uint64_t get() const { return _p; }
63
65 bool is_valid() const { return _p != ~0ULL; }
66
67private:
68 l4_uint64_t _p;
69};
70
71
81{
82public:
86 class Desc
87 {
88 public:
92 struct Flags
93 {
95 Flags() = default;
96
98 explicit Flags(l4_uint16_t v) : raw(v) {}
99
101 CXX_BITFIELD_MEMBER( 0, 0, next, raw);
103 CXX_BITFIELD_MEMBER( 1, 1, write, raw);
105 CXX_BITFIELD_MEMBER( 2, 2, indirect, raw);
106 };
107
112
116 void dump(unsigned idx) const
117 {
118 L4Re::Util::Dbg().printf("D[%04x]: %08llx (%x) f=%04x n=%04x\n",
119 idx, addr.get(),
120 len, static_cast<unsigned>(flags.raw),
121 static_cast<unsigned>(next));
122 }
123 };
124
128 class Avail
129 {
130 public:
134 struct Flags
135 {
137 Flags() = default;
138
140 explicit Flags(l4_uint16_t v) : raw(v) {}
141
143 CXX_BITFIELD_MEMBER( 0, 0, no_irq, raw);
144 };
145
149 };
150
155 {
156 Used_elem() = default;
157
168 };
169
173 class Used
174 {
175 public:
179 struct Flags
180 {
182 Flags() = default;
183
185 explicit Flags(l4_uint16_t v) : raw(v) {}
186
188 CXX_BITFIELD_MEMBER( 0, 0, no_notify, raw);
189 };
190
194 };
195
196protected:
197 Desc *_desc = nullptr;
198 Avail *_avail = nullptr;
199 Used *_used = nullptr;
200
203
209
213 Virtqueue() = default;
214
215 Virtqueue(Virtqueue const &) = delete;
216
217public:
223 void disable()
224 { _desc = 0; }
225
229 enum
230 {
231 Desc_align = 4, //< Alignment of the descriptor table.
232 Avail_align = 1, //< Alignment of the available ring.
233 Used_align = 2, //< Alignment of the used ring.
234 };
235
244 static unsigned long total_size(unsigned num)
245 {
246 static_assert(Desc_align >= Avail_align,
247 "virtqueue alignment assumptions broken");
248 return l4_round_size(desc_size(num) + avail_size(num), Used_align)
249 + used_size(num);
250 }
251
260 static unsigned long desc_size(unsigned num)
261 { return num * 16; }
262
268 static unsigned long desc_align()
269 { return Desc_align; }
270
278 static unsigned long avail_size(unsigned num)
279 { return 2 * num + 6; }
280
286 static unsigned long avail_align()
287 { return Avail_align; }
288
297 static unsigned long used_size(unsigned num)
298 { return 8 * num + 6; }
299
305 static unsigned long used_align()
306 { return Used_align; }
307
313 unsigned long total_size() const
314 {
315 return (reinterpret_cast<char *>(_used) - reinterpret_cast<char *>(_desc))
316 + used_size(num());
317 }
318
322 unsigned long avail_offset() const
323 { return reinterpret_cast<char *>(_avail) - reinterpret_cast<char *>(_desc); }
324
328 unsigned long used_offset() const
329 { return reinterpret_cast<char *>(_used) - reinterpret_cast<char *>(_desc); }
330
348 void setup(unsigned num, void *desc, void *avail, void *used)
349 {
350 if (num > 0x10000)
351 throw L4::Runtime_error(-L4_EINVAL, "Queue too large.");
352
353 _idx_mask = num - 1;
354 _desc = static_cast<Desc*>(desc);
355 _avail = static_cast<Avail*>(avail);
356 _used = static_cast<Used*>(used);
357
358 _current_avail = 0;
359
360 L4Re::Util::Dbg().printf("VQ[%p]: num=%d d:%p a:%p u:%p\n",
361 this, num, _desc, _avail, _used);
362 }
363
377 void setup_simple(unsigned num, void *ring)
378 {
379 l4_addr_t desc = reinterpret_cast<l4_addr_t>(ring);
380 l4_addr_t avail = l4_round_size(desc + desc_size(num), Avail_align);
381 void *used = reinterpret_cast<void *>(
382 l4_round_size(avail + avail_size(num), Used_align));
383 setup(num, ring, reinterpret_cast<void *>(avail), used);
384 }
385
391 void dump(Desc const *d) const
392 { d->dump(d - _desc); }
393
399 bool ready() const
400 { return L4_LIKELY(_desc != 0); }
401
403 unsigned num() const
404 { return _idx_mask + 1; }
405
413 bool no_notify_guest() const
414 {
415 return _avail->flags.no_irq();
416 }
417
425 bool no_notify_host() const
426 {
427 return _used->flags.no_notify();
428 }
429
435 void no_notify_host(bool value)
436 {
437 _used->flags.no_notify() = value;
438 }
439
448 l4_uint16_t get_avail_idx() const { return _avail->idx; }
449
456
457};
458
459namespace Driver {
460
470{
471private:
473 l4_uint16_t _next_free;
474
475public:
476 enum End_of_queue
477 {
478 // Indicates the end of the queue.
479 Eoq = 0xFFFF
480 };
481
482 Virtqueue() : _next_free(Eoq) {}
483
493 void initialize_rings(unsigned num)
494 {
495 _used->idx = 0;
496 _avail->idx = 0;
497
498 // setup the freelist
499 for (l4_uint16_t d = 0; d < num - 1; ++d)
500 _desc[d].next = d + 1;
501 _desc[num - 1].next = Eoq;
502 _next_free = 0;
503 }
504
521 void init_queue(unsigned num, void *desc, void *avail, void *used)
522 {
523 setup(num, desc, avail, used);
525 }
526
536 void init_queue(unsigned num, void *base)
537 {
538 setup_simple(num, base);
540 }
541
542
558 {
559 l4_uint16_t idx = _next_free;
560 if (idx == Eoq)
561 return Eoq;
562
563 _next_free = _desc[idx].next;
564
565 return idx;
566 }
567
574 {
575 if (descno > _idx_mask)
576 throw L4::Bounds_error();
577
578 _avail->ring[_avail->idx & _idx_mask] = descno; // _avail->idx expected to wrap
579 wmb();
580 ++_avail->idx;
581 }
582
590 {
591 if (descno > _idx_mask)
592 throw L4::Bounds_error();
593
594 return _desc[descno];
595 }
596
609 {
610 if (_current_avail == _used->idx)
611 return Eoq;
612
613 auto elem = _used->ring[_current_avail++ & _idx_mask];
614
615 if (len)
616 *len = elem.len;
617
618 return elem.id;
619 }
620
631 {
632 if (head > _idx_mask || tail > _idx_mask)
633 throw L4::Bounds_error();
634
635 _desc[tail].next = _next_free;
636 _next_free = head;
637 }
638};
639
640}
641} // namespace L4virtio
Access out of bounds.
Definition exceptions:279
Exception for an abstract runtime error.
Definition exceptions:129
Driver-side implementation of a Virtqueue.
Definition virtqueue:470
void free_descriptor(l4_uint16_t head, l4_uint16_t tail)
Free a chained list of descriptors in the descriptor queue.
Definition virtqueue:630
void enqueue_descriptor(l4_uint16_t descno)
Enqueue a descriptor in the available ring.
Definition virtqueue:573
void init_queue(unsigned num, void *base)
Initialize this virtqueue.
Definition virtqueue:536
l4_uint16_t alloc_descriptor()
Allocate and return an unused descriptor from the descriptor table.
Definition virtqueue:557
l4_uint16_t find_next_used(l4_uint32_t *len=nullptr)
Return the next finished block.
Definition virtqueue:608
void init_queue(unsigned num, void *desc, void *avail, void *used)
Initialize this virtqueue.
Definition virtqueue:521
Desc & desc(l4_uint16_t descno)
Return a reference to a descriptor in the descriptor table.
Definition virtqueue:589
void initialize_rings(unsigned num)
Initialize the descriptor table and the index structures of this queue.
Definition virtqueue:493
Pointer used in virtio descriptors.
Definition virtqueue:48
Ptr(l4_uint64_t vm_addr)
Make a Ptr from a raw 64bit address.
Definition virtqueue:59
l4_uint64_t get() const
Definition virtqueue:62
Invalid_type
Type for making an invalid (NULL) Ptr.
Definition virtqueue:51
@ Invalid
Use to set a Ptr to invalid (NULL)
Definition virtqueue:51
bool is_valid() const
Definition virtqueue:65
Ptr(Invalid_type)
Make and invalid Ptr.
Definition virtqueue:56
Type of available ring, this is read-only for the host.
Definition virtqueue:129
l4_uint16_t ring[]
array of available descriptor indexes.
Definition virtqueue:148
Flags flags
flags of available ring
Definition virtqueue:146
l4_uint16_t idx
available index written by guest
Definition virtqueue:147
Descriptor in the descriptor table.
Definition virtqueue:87
l4_uint16_t next
Index of the next chained descriptor.
Definition virtqueue:111
l4_uint32_t len
Length of described buffer.
Definition virtqueue:109
Flags flags
Descriptor flags.
Definition virtqueue:110
void dump(unsigned idx) const
Dump a single descriptor.
Definition virtqueue:116
Ptr< void > addr
Address stored in descriptor.
Definition virtqueue:108
Used_elem ring[]
array of used descriptors.
Definition virtqueue:193
l4_uint16_t idx
index of the last entry in the ring.
Definition virtqueue:192
Flags flags
flags of the used ring.
Definition virtqueue:191
Low-level Virtqueue.
Definition virtqueue:81
void no_notify_host(bool value)
Set the no-notify flag for this queue.
Definition virtqueue:435
void disable()
Completely disable the queue.
Definition virtqueue:223
void setup(unsigned num, void *desc, void *avail, void *used)
Enable this queue.
Definition virtqueue:348
static unsigned long desc_size(unsigned num)
Calculate the size of the descriptor table for num entries.
Definition virtqueue:260
l4_uint16_t get_tail_avail_idx() const
Get tail-available index stored in local state (for debugging).
Definition virtqueue:455
Used * _used
pointer to used ring.
Definition virtqueue:199
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:413
static unsigned long avail_align()
Get the alignment in zero LSBs needed for the available ring.
Definition virtqueue:286
void dump(Desc const *d) const
Dump descriptors for this queue.
Definition virtqueue:391
void setup_simple(unsigned num, void *ring)
Enable this queue.
Definition virtqueue:377
unsigned long avail_offset() const
Get the offset of the available ring from the descriptor table.
Definition virtqueue:322
static unsigned long used_align()
Get the alignment in zero LSBs needed for the used ring.
Definition virtqueue:305
static unsigned long total_size(unsigned num)
Calculate the total size for a virtqueue of the given dimensions.
Definition virtqueue:244
static unsigned long desc_align()
Get the alignment in zero LSBs needed for the descriptor table.
Definition virtqueue:268
static unsigned long used_size(unsigned num)
Calculate the size of the used ring for num entries.
Definition virtqueue:297
Virtqueue()=default
Create a disabled virtqueue.
unsigned long used_offset() const
Get the offset of the used ring from the descriptor table.
Definition virtqueue:328
static unsigned long avail_size(unsigned num)
Calculate the size of the available ring for num entries.
Definition virtqueue:278
unsigned long total_size() const
Calculate the total size of this virtqueue.
Definition virtqueue:313
bool ready() const
Test if this queue is in working state.
Definition virtqueue:399
l4_uint16_t _idx_mask
mask used for indexing into the descriptor table and the rings.
Definition virtqueue:208
Desc * _desc
pointer to descriptor table, NULL if queue is off.
Definition virtqueue:197
l4_uint16_t get_avail_idx() const
Get available index from available ring (for debugging).
Definition virtqueue:448
bool no_notify_host() const
Get the no notify flag of this queue.
Definition virtqueue:425
Avail * _avail
pointer to available ring.
Definition virtqueue:198
l4_uint16_t _current_avail
The life counter for the queue.
Definition virtqueue:202
unsigned num() const
Definition virtqueue:403
Error codes.
Base exceptions.
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:29
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:27
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:31
@ L4_EINVAL
Invalid argument.
Definition err.h:46
l4_addr_t l4_round_size(l4_addr_t value, unsigned char bits) L4_NOTHROW
Round value up to the next alignment with bits size.
Definition consts.h:488
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:274
Common L4 ABI Data Types.
L4-VIRTIO Transport C++ API.
Definition l4virtio:26
Flags of the available ring.
Definition virtqueue:135
constexpr no_irq_bfm_t::Val no_irq() const
Get the no_irq bits ( 0 to 0 ) of raw.
Definition virtqueue:143
Flags(l4_uint16_t v)
Make Flags from the raw value.
Definition virtqueue:140
l4_uint16_t raw
raw 16bit flags value of the available ring.
Definition virtqueue:136
Type for descriptor flags.
Definition virtqueue:93
constexpr next_bfm_t::Val next() const
Get the next bits ( 0 to 0 ) of raw.
Definition virtqueue:101
constexpr write_bfm_t::Val write() const
Get the write bits ( 1 to 1 ) of raw.
Definition virtqueue:103
Flags(l4_uint16_t v)
Make Flags from raw 16bit value.
Definition virtqueue:98
l4_uint16_t raw
raw flags value of a virtio descriptor.
Definition virtqueue:94
constexpr indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw.
Definition virtqueue:105
flags for the used ring.
Definition virtqueue:180
constexpr no_notify_bfm_t::Val no_notify() const
Get the no_notify bits ( 0 to 0 ) of raw.
Definition virtqueue:188
l4_uint16_t raw
raw flags value as specified by virtio.
Definition virtqueue:181
Flags(l4_uint16_t v)
make Flags from raw value
Definition virtqueue:185
Type of an element of the used ring.
Definition virtqueue:155
l4_uint32_t id
descriptor index
Definition virtqueue:166
l4_uint32_t len
length field
Definition virtqueue:167
Used_elem(l4_uint16_t id, l4_uint32_t len)
Initialize a used ring element.
Definition virtqueue:165