L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
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// __ARM_ARCH_7A__ not defined by Clang
19#if defined(__ARM_ARCH_7A__) \
20 || ( defined(__ARM_ARCH) && __ARM_ARCH == 7 \
21 && defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE >= 'A')
22static inline void wmb() { asm volatile ("dmb" : : : "memory"); }
23static inline void rmb() { asm volatile ("dmb" : : : "memory"); }
24// __ARM_ARCH_8A__ not defined by Clang
25#elif defined(__ARM_ARCH_8A) \
26 || ( defined(__ARM_ARCH) && __ARM_ARCH == 8 \
27 && defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE >= 'A') \
28 || (defined(__ARM_ARCH) && __ARM_ARCH > 8)
29static inline void wmb() { asm volatile ("dsb ishst" : : : "memory"); }
30static inline void rmb() { asm volatile ("dsb ishld" : : : "memory"); }
31#elif defined(__mips__)
32static inline void wmb() { asm volatile ("sync" : : : "memory"); }
33static inline void rmb() { asm volatile ("sync" : : : "memory"); }
34#elif defined(__amd64__) || defined(__i386__) || defined(__i686__)
35static inline void wmb() { asm volatile ("sfence" : : : "memory"); }
36static inline void rmb() { asm volatile ("lfence" : : : "memory"); }
37#elif defined(__riscv)
38static inline void wmb() { asm volatile ("fence ow, ow" : : : "memory"); }
39static inline void rmb() { asm volatile ("fence ir, ir" : : : "memory"); }
40#else
41#warning Missing proper memory write barrier
42static inline void wmb() { asm volatile ("" : : : "memory"); }
43static inline void rmb() { asm volatile ("" : : : "memory"); }
44#endif
45
46
53template< typename T >
54class Ptr
55{
56public:
59
60 Ptr() = default;
61
63 Ptr(Invalid_type) : _p(~0ULL) {}
64
66 explicit Ptr(l4_uint64_t vm_addr) : _p(vm_addr) {}
67
69 l4_uint64_t get() const { return _p; }
70
72 bool is_valid() const { return _p != ~0ULL; }
73
74private:
75 l4_uint64_t _p;
76};
77
78
88{
89public:
93 class Desc
94 {
95 public:
99 struct Flags
100 {
102 Flags() = default;
103
105 explicit Flags(l4_uint16_t v) : raw(v) {}
106
108 CXX_BITFIELD_MEMBER( 0, 0, next, raw);
110 CXX_BITFIELD_MEMBER( 1, 1, write, raw);
112 CXX_BITFIELD_MEMBER( 2, 2, indirect, raw);
113 };
114
119
123 void dump(unsigned idx) const
124 {
125 L4Re::Util::Dbg().printf("D[%04x]: %08llx (%x) f=%04x n=%04x\n",
126 idx, addr.get(),
127 len, static_cast<unsigned>(flags.raw),
128 static_cast<unsigned>(next));
129 }
130 };
131
135 class Avail
136 {
137 public:
141 struct Flags
142 {
144 Flags() = default;
145
147 explicit Flags(l4_uint16_t v) : raw(v) {}
148
150 CXX_BITFIELD_MEMBER( 0, 0, no_irq, raw);
151 };
152
156 };
157
162 {
163 Used_elem() = default;
164
175 };
176
180 class Used
181 {
182 public:
186 struct Flags
187 {
189 Flags() = default;
190
192 explicit Flags(l4_uint16_t v) : raw(v) {}
193
195 CXX_BITFIELD_MEMBER( 0, 0, no_notify, raw);
196 };
197
201 };
202
203protected:
204 Desc *_desc = nullptr;
205 Avail *_avail = nullptr;
206 Used *_used = nullptr;
207
210
216
220 Virtqueue() = default;
221
222 Virtqueue(Virtqueue const &) = delete;
223
224public:
230 void disable()
231 { _desc = 0; }
232
236 enum
237 {
238 Desc_align = 4, //< Alignment of the descriptor table.
239 Avail_align = 1, //< Alignment of the available ring.
240 Used_align = 2, //< Alignment of the used ring.
241 };
242
251 static unsigned long total_size(unsigned num)
252 {
253 static_assert(Desc_align >= Avail_align,
254 "virtqueue alignment assumptions broken");
255 return l4_round_size(desc_size(num) + avail_size(num), Used_align)
256 + used_size(num);
257 }
258
267 static unsigned long desc_size(unsigned num)
268 { return num * 16; }
269
275 static unsigned long desc_align()
276 { return Desc_align; }
277
285 static unsigned long avail_size(unsigned num)
286 { return 2 * num + 6; }
287
293 static unsigned long avail_align()
294 { return Avail_align; }
295
304 static unsigned long used_size(unsigned num)
305 { return 8 * num + 6; }
306
312 static unsigned long used_align()
313 { return Used_align; }
314
320 unsigned long total_size() const
321 {
322 return (reinterpret_cast<char *>(_used) - reinterpret_cast<char *>(_desc))
323 + used_size(num());
324 }
325
329 unsigned long avail_offset() const
330 { return reinterpret_cast<char *>(_avail) - reinterpret_cast<char *>(_desc); }
331
335 unsigned long used_offset() const
336 { return reinterpret_cast<char *>(_used) - reinterpret_cast<char *>(_desc); }
337
355 void setup(unsigned num, void *desc, void *avail, void *used)
356 {
357 if (num > 0x10000)
358 throw L4::Runtime_error(-L4_EINVAL, "Queue too large.");
359
360 _idx_mask = num - 1;
361 _desc = static_cast<Desc*>(desc);
362 _avail = static_cast<Avail*>(avail);
363 _used = static_cast<Used*>(used);
364
365 _current_avail = 0;
366
367 L4Re::Util::Dbg().printf("VQ[%p]: num=%d d:%p a:%p u:%p\n",
368 this, num, _desc, _avail, _used);
369 }
370
384 void setup_simple(unsigned num, void *ring)
385 {
386 l4_addr_t desc = reinterpret_cast<l4_addr_t>(ring);
387 l4_addr_t avail = l4_round_size(desc + desc_size(num), Avail_align);
388 void *used = reinterpret_cast<void *>(
389 l4_round_size(avail + avail_size(num), Used_align));
390 setup(num, ring, reinterpret_cast<void *>(avail), used);
391 }
392
398 void dump(Desc const *d) const
399 { d->dump(d - _desc); }
400
406 bool ready() const
407 { return L4_LIKELY(_desc != 0); }
408
410 unsigned num() const
411 { return _idx_mask + 1; }
412
420 bool no_notify_guest() const
421 {
422 return _avail->flags.no_irq();
423 }
424
432 bool no_notify_host() const
433 {
434 return _used->flags.no_notify();
435 }
436
442 void no_notify_host(bool value)
443 {
444 _used->flags.no_notify() = value;
445 }
446
455 l4_uint16_t get_avail_idx() const { return _avail->idx; }
456
463
464};
465
466namespace Driver {
467
477{
478private:
480 l4_uint16_t _next_free;
481
482public:
483 enum End_of_queue
484 {
485 // Indicates the end of the queue.
486 Eoq = 0xFFFF
487 };
488
489 Virtqueue() : _next_free(Eoq) {}
490
500 void initialize_rings(unsigned num)
501 {
502 _used->idx = 0;
503 _avail->idx = 0;
504
505 // setup the freelist
506 for (l4_uint16_t d = 0; d < num - 1; ++d)
507 _desc[d].next = d + 1;
508 _desc[num - 1].next = Eoq;
509 _next_free = 0;
510 }
511
528 void init_queue(unsigned num, void *desc, void *avail, void *used)
529 {
530 setup(num, desc, avail, used);
532 }
533
543 void init_queue(unsigned num, void *base)
544 {
545 setup_simple(num, base);
547 }
548
549
565 {
566 l4_uint16_t idx = _next_free;
567 if (idx == Eoq)
568 return Eoq;
569
570 _next_free = _desc[idx].next;
571
572 return idx;
573 }
574
581 {
582 if (descno > _idx_mask)
583 throw L4::Bounds_error();
584
585 _avail->ring[_avail->idx & _idx_mask] = descno; // _avail->idx expected to wrap
586 wmb();
587 ++_avail->idx;
588 }
589
597 {
598 if (descno > _idx_mask)
599 throw L4::Bounds_error();
600
601 return _desc[descno];
602 }
603
616 {
617 if (_current_avail == _used->idx)
618 return Eoq;
619
620 auto elem = _used->ring[_current_avail++ & _idx_mask];
621
622 if (len)
623 *len = elem.len;
624
625 return elem.id;
626 }
627
638 {
639 if (head > _idx_mask || tail > _idx_mask)
640 throw L4::Bounds_error();
641
642 _desc[tail].next = _next_free;
643 _next_free = head;
644 }
645};
646
647}
648} // namespace L4virtio
Access out of bounds.
Definition exceptions:290
Exception for an abstract runtime error.
Definition exceptions:140
Driver-side implementation of a Virtqueue.
Definition virtqueue:477
void free_descriptor(l4_uint16_t head, l4_uint16_t tail)
Free a chained list of descriptors in the descriptor queue.
Definition virtqueue:637
void enqueue_descriptor(l4_uint16_t descno)
Enqueue a descriptor in the available ring.
Definition virtqueue:580
void init_queue(unsigned num, void *base)
Initialize this virtqueue.
Definition virtqueue:543
l4_uint16_t alloc_descriptor()
Allocate and return an unused descriptor from the descriptor table.
Definition virtqueue:564
l4_uint16_t find_next_used(l4_uint32_t *len=nullptr)
Return the next finished block.
Definition virtqueue:615
void init_queue(unsigned num, void *desc, void *avail, void *used)
Initialize this virtqueue.
Definition virtqueue:528
Desc & desc(l4_uint16_t descno)
Return a reference to a descriptor in the descriptor table.
Definition virtqueue:596
void initialize_rings(unsigned num)
Initialize the descriptor table and the index structures of this queue.
Definition virtqueue:500
Pointer used in virtio descriptors.
Definition virtqueue:55
Ptr(l4_uint64_t vm_addr)
Make a Ptr from a raw 64bit address.
Definition virtqueue:66
l4_uint64_t get() const
Definition virtqueue:69
Invalid_type
Type for making an invalid (NULL) Ptr.
Definition virtqueue:58
@ Invalid
Use to set a Ptr to invalid (NULL)
Definition virtqueue:58
bool is_valid() const
Definition virtqueue:72
Ptr(Invalid_type)
Make and invalid Ptr.
Definition virtqueue:63
Type of available ring, this is read-only for the host.
Definition virtqueue:136
l4_uint16_t ring[]
array of available descriptor indexes.
Definition virtqueue:155
Flags flags
flags of available ring
Definition virtqueue:153
l4_uint16_t idx
available index written by guest
Definition virtqueue:154
Descriptor in the descriptor table.
Definition virtqueue:94
l4_uint16_t next
Index of the next chained descriptor.
Definition virtqueue:118
l4_uint32_t len
Length of described buffer.
Definition virtqueue:116
Flags flags
Descriptor flags.
Definition virtqueue:117
void dump(unsigned idx) const
Dump a single descriptor.
Definition virtqueue:123
Ptr< void > addr
Address stored in descriptor.
Definition virtqueue:115
Used_elem ring[]
array of used descriptors.
Definition virtqueue:200
l4_uint16_t idx
index of the last entry in the ring.
Definition virtqueue:199
Flags flags
flags of the used ring.
Definition virtqueue:198
Low-level Virtqueue.
Definition virtqueue:88
void no_notify_host(bool value)
Set the no-notify flag for this queue.
Definition virtqueue:442
void disable()
Completely disable the queue.
Definition virtqueue:230
void setup(unsigned num, void *desc, void *avail, void *used)
Enable this queue.
Definition virtqueue:355
static unsigned long desc_size(unsigned num)
Calculate the size of the descriptor table for num entries.
Definition virtqueue:267
l4_uint16_t get_tail_avail_idx() const
Get tail-available index stored in local state (for debugging).
Definition virtqueue:462
Used * _used
pointer to used ring.
Definition virtqueue:206
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:420
static unsigned long avail_align()
Get the alignment in zero LSBs needed for the available ring.
Definition virtqueue:293
void dump(Desc const *d) const
Dump descriptors for this queue.
Definition virtqueue:398
void setup_simple(unsigned num, void *ring)
Enable this queue.
Definition virtqueue:384
unsigned long avail_offset() const
Get the offset of the available ring from the descriptor table.
Definition virtqueue:329
static unsigned long used_align()
Get the alignment in zero LSBs needed for the used ring.
Definition virtqueue:312
static unsigned long total_size(unsigned num)
Calculate the total size for a virtqueue of the given dimensions.
Definition virtqueue:251
static unsigned long desc_align()
Get the alignment in zero LSBs needed for the descriptor table.
Definition virtqueue:275
static unsigned long used_size(unsigned num)
Calculate the size of the used ring for num entries.
Definition virtqueue:304
Virtqueue()=default
Create a disabled virtqueue.
unsigned long used_offset() const
Get the offset of the used ring from the descriptor table.
Definition virtqueue:335
static unsigned long avail_size(unsigned num)
Calculate the size of the available ring for num entries.
Definition virtqueue:285
unsigned long total_size() const
Calculate the total size of this virtqueue.
Definition virtqueue:320
bool ready() const
Test if this queue is in working state.
Definition virtqueue:406
l4_uint16_t _idx_mask
mask used for indexing into the descriptor table and the rings.
Definition virtqueue:215
Desc * _desc
pointer to descriptor table, NULL if queue is off.
Definition virtqueue:204
l4_uint16_t get_avail_idx() const
Get available index from available ring (for debugging).
Definition virtqueue:455
bool no_notify_host() const
Get the no notify flag of this queue.
Definition virtqueue:432
Avail * _avail
pointer to available ring.
Definition virtqueue:205
l4_uint16_t _current_avail
The life counter for the queue.
Definition virtqueue:209
unsigned num() const
Definition virtqueue:410
Error codes.
Base exceptions.
unsigned long l4_addr_t
Address type.
Definition l4int.h:45
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition l4int.h:40
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition l4int.h:38
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:42
@ L4_EINVAL
Invalid argument.
Definition err.h:57
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:473
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:295
Common L4 ABI Data Types.
L4-VIRTIO Transport C++ API.
Definition l4virtio:26
Flags of the available ring.
Definition virtqueue:142
constexpr no_irq_bfm_t::Val no_irq() const
Get the no_irq bits ( 0 to 0 ) of raw.
Definition virtqueue:150
Flags(l4_uint16_t v)
Make Flags from the raw value.
Definition virtqueue:147
l4_uint16_t raw
raw 16bit flags value of the available ring.
Definition virtqueue:143
Type for descriptor flags.
Definition virtqueue:100
constexpr next_bfm_t::Val next() const
Get the next bits ( 0 to 0 ) of raw.
Definition virtqueue:108
constexpr write_bfm_t::Val write() const
Get the write bits ( 1 to 1 ) of raw.
Definition virtqueue:110
Flags(l4_uint16_t v)
Make Flags from raw 16bit value.
Definition virtqueue:105
l4_uint16_t raw
raw flags value of a virtio descriptor.
Definition virtqueue:101
constexpr indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw.
Definition virtqueue:112
flags for the used ring.
Definition virtqueue:187
constexpr no_notify_bfm_t::Val no_notify() const
Get the no_notify bits ( 0 to 0 ) of raw.
Definition virtqueue:195
l4_uint16_t raw
raw flags value as specified by virtio.
Definition virtqueue:188
Flags(l4_uint16_t v)
make Flags from raw value
Definition virtqueue:192
Type of an element of the used ring.
Definition virtqueue:162
l4_uint32_t id
descriptor index
Definition virtqueue:173
l4_uint32_t len
length field
Definition virtqueue:174
Used_elem(l4_uint16_t id, l4_uint32_t len)
Initialize a used ring element.
Definition virtqueue:172