L4Re Operating System Framework – Interface and Usage Documentation
Loading...
Searching...
No Matches
virtqueue
1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2014 Alexander Warg <warg@os.inf.tu-dresden.de>
4 *
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU General Public License 2.
7 * Please see the COPYING-GPL-2 file for details.
8 *
9 * As a special exception, you may use this file as part of a free software
10 * library without restriction. Specifically, if other files instantiate
11 * templates or use macros or inline functions from this file, or you compile
12 * this file and link it with other files to produce an executable, this
13 * file does not by itself cause the resulting executable to be covered by
14 * the GNU General Public License. This exception does not however
15 * invalidate any other reasons why the executable file might be covered by
16 * the GNU General Public License.
17 */
18
19#include <l4/re/util/debug>
20#include <l4/sys/types.h>
21#include <l4/sys/err.h>
22#include <l4/cxx/bitfield>
23#include <l4/cxx/exceptions>
24#include <cstdint>
25
26#pragma once
27
28namespace L4virtio {
29
30// __ARM_ARCH_7A__ not defined by Clang
31#if defined(__ARM_ARCH_7A__) \
32 || ( defined(__ARM_ARCH) && __ARM_ARCH == 7 \
33 && defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE >= 'A')
34static inline void wmb() { asm volatile ("dmb" : : : "memory"); }
35static inline void rmb() { asm volatile ("dmb" : : : "memory"); }
36// __ARM_ARCH_8A__ not defined by Clang
37#elif defined(__ARM_ARCH_8A) \
38 || ( defined(__ARM_ARCH) && __ARM_ARCH == 8 \
39 && defined(__ARM_ARCH_PROFILE) && __ARM_ARCH_PROFILE >= 'A') \
40 || (defined(__ARM_ARCH) && __ARM_ARCH > 8)
41static inline void wmb() { asm volatile ("dsb ishst" : : : "memory"); }
42static inline void rmb() { asm volatile ("dsb ishld" : : : "memory"); }
43#elif defined(__mips__)
44static inline void wmb() { asm volatile ("sync" : : : "memory"); }
45static inline void rmb() { asm volatile ("sync" : : : "memory"); }
46#elif defined(__amd64__) || defined(__i386__) || defined(__i686__)
47static inline void wmb() { asm volatile ("sfence" : : : "memory"); }
48static inline void rmb() { asm volatile ("lfence" : : : "memory"); }
49#else
50#warning Missing proper memory write barrier
51static inline void wmb() { asm volatile ("" : : : "memory"); }
52static inline void rmb() { asm volatile ("" : : : "memory"); }
53#endif
54
55
62template< typename T >
63class Ptr
64{
65public:
68
69 Ptr() = default;
70
72 Ptr(Invalid_type) : _p(~0ULL) {}
73
75 explicit Ptr(l4_uint64_t vm_addr) : _p(vm_addr) {}
76
78 l4_uint64_t get() const { return _p; }
79
81 bool is_valid() const { return _p != ~0ULL; }
82
83private:
84 l4_uint64_t _p;
85};
86
87
97{
98public:
102 class Desc
103 {
104 public:
108 struct Flags
109 {
111 Flags() = default;
112
114 explicit Flags(l4_uint16_t v) : raw(v) {}
115
117 CXX_BITFIELD_MEMBER( 0, 0, next, raw);
119 CXX_BITFIELD_MEMBER( 1, 1, write, raw);
121 CXX_BITFIELD_MEMBER( 2, 2, indirect, raw);
122 };
123
128
132 void dump(unsigned idx) const
133 {
134 L4Re::Util::Dbg().printf("D[%04x]: %08llx (%x) f=%04x n=%04x\n",
135 idx, addr.get(),
136 len, (unsigned)flags.raw, (unsigned)next);
137 }
138 };
139
143 class Avail
144 {
145 public:
149 struct Flags
150 {
152 Flags() = default;
153
155 explicit Flags(l4_uint16_t v) : raw(v) {}
156
158 CXX_BITFIELD_MEMBER( 0, 0, no_irq, raw);
159 };
160
164 };
165
170 {
171 Used_elem() = default;
172
183 };
184
188 class Used
189 {
190 public:
194 struct Flags
195 {
197 Flags() = default;
198
200 explicit Flags(l4_uint16_t v) : raw(v) {}
201
203 CXX_BITFIELD_MEMBER( 0, 0, no_notify, raw);
204 };
205
209 };
210
211protected:
215
218
224
229 Virtqueue(Virtqueue const &) = delete;
230
231public:
237 void disable()
238 { _desc = 0; }
239
243 enum
244 {
245 Desc_align = 4, //< Alignment of the descriptor table.
246 Avail_align = 1, //< Alignment of the available ring.
247 Used_align = 2, //< Alignment of the used ring.
248 };
249
258 static unsigned long total_size(unsigned num)
259 {
260 static_assert(Desc_align >= Avail_align,
261 "virtqueue alignment assumptions broken");
262 return l4_round_size(desc_size(num) + avail_size(num), Used_align)
263 + used_size(num);
264 }
265
274 static unsigned long desc_size(unsigned num)
275 { return num * 16; }
276
282 static unsigned long desc_align()
283 { return Desc_align; }
284
292 static unsigned long avail_size(unsigned num)
293 { return 2 * num + 6; }
294
300 static unsigned long avail_align()
301 { return Avail_align; }
302
311 static unsigned long used_size(unsigned num)
312 { return 8 * num + 6; }
313
319 static unsigned long used_align()
320 { return Used_align; }
321
327 unsigned long total_size() const
328 {
329 return ((char *) _used - (char *) _desc)
330 + used_size(num());
331 }
332
336 unsigned long avail_offset() const
337 { return (char const *)_avail - (char const *)_desc; }
338
342 unsigned long used_offset() const
343 { return (char const *)_used - (char const *)_desc; }
344
362 void setup(unsigned num, void *desc, void *avail, void *used)
363 {
364 if (num > 0x10000)
365 throw L4::Runtime_error(-L4_EINVAL, "Queue too large.");
366
367 _idx_mask = num - 1;
368 _desc = (Desc*)desc;
369 _avail = (Avail*)avail;
370 _used = (Used*)used;
371
372 _current_avail = 0;
373
374 L4Re::Util::Dbg().printf("VQ[%p]: num=%d d:%p a:%p u:%p\n",
375 this, num, _desc, _avail, _used);
376 }
377
391 void setup_simple(unsigned num, void *ring)
392 {
393 l4_addr_t desc = reinterpret_cast<l4_addr_t>(ring);
394 l4_addr_t avail = l4_round_size(desc + desc_size(num), Avail_align);
395 l4_addr_t used = l4_round_size(avail + avail_size(num), Used_align);
396 setup(num, (void *)desc, (void *)avail, (void *)used);
397 }
398
404 void dump(Desc const *d) const
405 { d->dump(d - _desc); }
406
412 bool ready() const
413 { return L4_LIKELY(_desc != 0); }
414
416 unsigned num() const
417 { return _idx_mask + 1; }
418
426 bool no_notify_guest() const
427 {
428 return _avail->flags.no_irq();
429 }
430
438 bool no_notify_host() const
439 {
440 return _used->flags.no_notify();
441 }
442
448 void no_notify_host(bool value)
449 {
450 _used->flags.no_notify() = value;
451 }
452
461 l4_uint16_t get_avail_idx() const { return _avail->idx; }
462
469
470};
471
472namespace Driver {
473
483{
484private:
486 l4_uint16_t _next_free;
487
488public:
489 enum End_of_queue
490 {
491 // Indicates the end of the queue.
492 Eoq = 0xFFFF
493 };
494
495 Virtqueue() : _next_free(Eoq) {}
496
506 void initialize_rings(unsigned num)
507 {
508 _used->idx = 0;
509 _avail->idx = 0;
510
511 // setup the freelist
512 for (l4_uint16_t d = 0; d < num - 1; ++d)
513 _desc[d].next = d + 1;
514 _desc[num - 1].next = Eoq;
515 _next_free = 0;
516 }
517
534 void init_queue(unsigned num, void *desc, void *avail, void *used)
535 {
536 setup(num, desc, avail, used);
538 }
539
549 void init_queue(unsigned num, void *base)
550 {
551 setup_simple(num, base);
553 }
554
555
571 {
572 l4_uint16_t idx = _next_free;
573 if (idx == Eoq)
574 return Eoq;
575
576 _next_free = _desc[idx].next;
577
578 return idx;
579 }
580
587 {
588 if (descno > _idx_mask)
589 throw L4::Bounds_error();
590
591 _avail->ring[_avail->idx & _idx_mask] = descno; // _avail->idx expected to wrap
592 wmb();
593 ++_avail->idx;
594 }
595
603 {
604 if (descno > _idx_mask)
605 throw L4::Bounds_error();
606
607 return _desc[descno];
608 }
609
622 {
623 if (_current_avail == _used->idx)
624 return Eoq;
625
626 auto elem = _used->ring[_current_avail++ & _idx_mask];
627
628 if (len)
629 *len = elem.len;
630
631 return elem.id;
632 }
633
644 {
645 if (head > _idx_mask || tail > _idx_mask)
646 throw L4::Bounds_error();
647
648 _desc[tail].next = _next_free;
649 _next_free = head;
650 }
651};
652
653}
654} // 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:483
void free_descriptor(l4_uint16_t head, l4_uint16_t tail)
Free a chained list of descriptors in the descriptor queue.
Definition virtqueue:643
void enqueue_descriptor(l4_uint16_t descno)
Enqueue a descriptor in the available ring.
Definition virtqueue:586
void init_queue(unsigned num, void *base)
Initialize this virtqueue.
Definition virtqueue:549
l4_uint16_t alloc_descriptor()
Allocate and return an unused descriptor from the descriptor table.
Definition virtqueue:570
l4_uint16_t find_next_used(l4_uint32_t *len=nullptr)
Return the next finished block.
Definition virtqueue:621
void init_queue(unsigned num, void *desc, void *avail, void *used)
Initialize this virtqueue.
Definition virtqueue:534
Desc & desc(l4_uint16_t descno)
Return a reference to a descriptor in the descriptor table.
Definition virtqueue:602
void initialize_rings(unsigned num)
Initialize the descriptor table and the index structures of this queue.
Definition virtqueue:506
Pointer used in virtio descriptors.
Definition virtqueue:64
Ptr(l4_uint64_t vm_addr)
Make a Ptr from a raw 64bit address.
Definition virtqueue:75
l4_uint64_t get() const
Definition virtqueue:78
Invalid_type
Type for making an invalid (NULL) Ptr.
Definition virtqueue:67
@ Invalid
Use to set a Ptr to invalid (NULL)
Definition virtqueue:67
bool is_valid() const
Definition virtqueue:81
Ptr(Invalid_type)
Make and invalid Ptr.
Definition virtqueue:72
Type of available ring, this is read-only for the host.
Definition virtqueue:144
l4_uint16_t ring[]
array of available descriptor indexes.
Definition virtqueue:163
Flags flags
flags of available ring
Definition virtqueue:161
l4_uint16_t idx
available index written by guest
Definition virtqueue:162
Descriptor in the descriptor table.
Definition virtqueue:103
l4_uint16_t next
Index of the next chained descriptor.
Definition virtqueue:127
l4_uint32_t len
Length of described buffer.
Definition virtqueue:125
Flags flags
Descriptor flags.
Definition virtqueue:126
void dump(unsigned idx) const
Dump a single descriptor.
Definition virtqueue:132
Ptr< void > addr
Address stored in descriptor.
Definition virtqueue:124
Used_elem ring[]
array of used descriptors.
Definition virtqueue:208
l4_uint16_t idx
index of the last entry in the ring.
Definition virtqueue:207
Flags flags
flags of the used ring.
Definition virtqueue:206
Low-level Virtqueue.
Definition virtqueue:97
void no_notify_host(bool value)
Set the no-notify flag for this queue.
Definition virtqueue:448
void disable()
Completely disable the queue.
Definition virtqueue:237
void setup(unsigned num, void *desc, void *avail, void *used)
Enable this queue.
Definition virtqueue:362
static unsigned long desc_size(unsigned num)
Calculate the size of the descriptor table for num entries.
Definition virtqueue:274
l4_uint16_t get_tail_avail_idx() const
Get tail-available index stored in local state (for debugging).
Definition virtqueue:468
Used * _used
pointer to used ring.
Definition virtqueue:214
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:426
static unsigned long avail_align()
Get the alignment in zero LSBs needed for the available ring.
Definition virtqueue:300
void dump(Desc const *d) const
Dump descriptors for this queue.
Definition virtqueue:404
void setup_simple(unsigned num, void *ring)
Enable this queue.
Definition virtqueue:391
unsigned long avail_offset() const
Get the offset of the available ring from the descriptor table.
Definition virtqueue:336
static unsigned long used_align()
Get the alignment in zero LSBs needed for the used ring.
Definition virtqueue:319
static unsigned long total_size(unsigned num)
Calculate the total size for a virtqueue of the given dimensions.
Definition virtqueue:258
static unsigned long desc_align()
Get the alignment in zero LSBs needed for the descriptor table.
Definition virtqueue:282
static unsigned long used_size(unsigned num)
Calculate the size of the used ring for num entries.
Definition virtqueue:311
unsigned long used_offset() const
Get the offset of the used ring from the descriptor table.
Definition virtqueue:342
static unsigned long avail_size(unsigned num)
Calculate the size of the available ring for num entries.
Definition virtqueue:292
unsigned long total_size() const
Calculate the total size of this virtqueue.
Definition virtqueue:327
Virtqueue()
Create a disabled virtqueue.
Definition virtqueue:228
bool ready() const
Test if this queue is in working state.
Definition virtqueue:412
l4_uint16_t _idx_mask
mask used for indexing into the descriptor table and the rings.
Definition virtqueue:223
Desc * _desc
pointer to descriptor table, NULL if queue is off.
Definition virtqueue:212
l4_uint16_t get_avail_idx() const
Get available index from available ring (for debugging).
Definition virtqueue:461
bool no_notify_host() const
Get the no notify flag of this queue.
Definition virtqueue:438
Avail * _avail
pointer to available ring.
Definition virtqueue:213
l4_uint16_t _current_avail
The life counter for the queue.
Definition virtqueue:217
unsigned num() const
Definition virtqueue:416
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:56
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:284
Common L4 ABI Data Types.
L4-VIRTIO Transport C++ API.
Definition l4virtio:26
Flags of the available ring.
Definition virtqueue:150
no_irq_bfm_t::Val no_irq() const
Get the no_irq bits ( 0 to 0 ) of raw.
Definition virtqueue:158
Flags(l4_uint16_t v)
Make Flags from the raw value.
Definition virtqueue:155
l4_uint16_t raw
raw 16bit flags value of the available ring.
Definition virtqueue:151
Type for descriptor flags.
Definition virtqueue:109
write_bfm_t::Val write() const
Get the write bits ( 1 to 1 ) of raw.
Definition virtqueue:119
next_bfm_t::Val next() const
Get the next bits ( 0 to 0 ) of raw.
Definition virtqueue:117
indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw.
Definition virtqueue:121
Flags(l4_uint16_t v)
Make Flags from raw 16bit value.
Definition virtqueue:114
l4_uint16_t raw
raw flags value of a virtio descriptor.
Definition virtqueue:110
flags for the used ring.
Definition virtqueue:195
l4_uint16_t raw
raw flags value as specified by virtio.
Definition virtqueue:196
no_notify_bfm_t::Val no_notify() const
Get the no_notify bits ( 0 to 0 ) of raw.
Definition virtqueue:203
Flags(l4_uint16_t v)
make Flags from raw value
Definition virtqueue:200
Type of an element of the used ring.
Definition virtqueue:170
l4_uint32_t id
descriptor index
Definition virtqueue:181
l4_uint32_t len
length field
Definition virtqueue:182
Used_elem(l4_uint16_t id, l4_uint32_t len)
Initialize a used ring element.
Definition virtqueue:180