L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
virtio
1// vi:ft=cpp
2/* SPDX-License-Identifier: MIT */
3/*
4 * Copyright (C) 2014-2020, 2023-2024 Kernkonzept GmbH.
5 * Author(s): Alexander Warg <alexander.warg@kernkonzept.com>
6 *
7 */
8#pragma once
9
10#include <l4/sys/types.h>
11#include <l4/cxx/bitfield>
12#include <l4/cxx/minmax>
13#include <l4/cxx/utils>
14
15#include <limits.h>
16#include <string.h>
17#include <stdio.h>
18
19#include "../virtqueue"
20
26namespace L4virtio {
27namespace Svr {
28
33{
34 unsigned char raw;
35 Dev_status() = default;
36
38 explicit Dev_status(l4_uint32_t v) : raw(v) {}
39
40 CXX_BITFIELD_MEMBER(0, 0, acked, raw);
41 CXX_BITFIELD_MEMBER(1, 1, driver, raw);
42 CXX_BITFIELD_MEMBER(2, 2, driver_ok, raw);
43 CXX_BITFIELD_MEMBER(3, 3, features_ok, raw);
44 CXX_BITFIELD_MEMBER(6, 7, fail_state, raw);
45 CXX_BITFIELD_MEMBER(6, 6, device_needs_reset, raw);
46 CXX_BITFIELD_MEMBER(7, 7, failed, raw);
47
57 bool running() const
58 {
59 return (raw == 0xf);
60 }
61};
62
67{
69 Dev_features() = default;
70
72 explicit Dev_features(l4_uint32_t v) : raw(v) {}
73
74 CXX_BITFIELD_MEMBER(28, 28, ring_indirect_desc, raw);
75 CXX_BITFIELD_MEMBER(29, 29, ring_event_idx, raw);
76};
77
78
88{
89public:
94 {
95 friend class Virtqueue;
96 private:
97 Virtqueue::Desc const *_d;
98 Head_desc(Virtqueue *r, unsigned i) : _d(r->desc(i)) {}
99
100 public:
102 Head_desc() : _d(0) {}
103
105 bool valid() const { return _d; }
106
108 explicit operator bool () const
109 { return valid(); }
110
112 Desc const *desc() const
113 { return _d; }
114 };
115
116 struct Request : Head_desc
117 {
118 Virtqueue *ring = nullptr;
119 Request() = default;
120 private:
121 friend class Virtqueue;
122 Request(Virtqueue *r, unsigned i) : Head_desc(r, i), ring(r) {}
123 };
124
125
136 Request next_avail()
137 {
139 {
140 rmb();
141 unsigned head = _current_avail & _idx_mask;
143 return Request(this, _avail->ring[head]);
144 }
145 return Request();
146 }
147
160 void rewind_avail(Head_desc const &d)
161 {
162 unsigned head_idx = d._d - _desc;
163 // Calculate the distance between _current_avail and head_idx, taking into
164 // account that _current_avail might have wrapped around with respect to
165 // _idx_mask in the meantime.
166 _current_avail -= (_current_avail - head_idx) & _idx_mask;
167 }
168
175 bool desc_avail() const
176 {
177 return _current_avail != _avail->idx;
178 }
179
190 void consumed(Head_desc const &r, l4_uint32_t len = 0)
191 {
193 _used->ring[i] = Used_elem(r._d - _desc, len);
194 wmb();
195 ++_used->idx;
196 }
197
212 template<typename ITER>
213 void consumed(ITER const &begin, ITER const &end)
214 {
215 l4_uint16_t added = 0;
216 l4_uint16_t idx = _used->idx;
217
218 for (auto elem = begin ; elem != end; ++elem, ++added)
219 _used->ring[(idx + added) & _idx_mask]
220 = Used_elem(elem->first._d - _desc, elem->second);
221
222 wmb();
223 _used->idx += added;
224 }
225
239 template<typename QUEUE_OBSERVER>
240 void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len = 0)
241 {
242 consumed(d, len);
243 o->notify_queue(this);
244 d._d = 0;
245 }
246
261 template<typename ITER, typename QUEUE_OBSERVER>
262 void finish(ITER const &begin, ITER const &end, QUEUE_OBSERVER *o)
263 {
264 consumed(begin, end);
265 o->notify_queue(this);
266 }
267
274 {
275 if (L4_LIKELY(ready()))
276 _used->flags.no_notify() = 1;
277 }
278
285 {
286 if (L4_LIKELY(ready()))
287 _used->flags.no_notify() = 0;
288 }
289
298 Desc const *desc(unsigned idx) const
299 { return _desc + idx; }
300
301};
302
307{
308 char *pos;
310
311 Data_buffer() = default;
312
322 template<typename T>
323 explicit Data_buffer(T *p)
324 : pos(reinterpret_cast<char *>(p)), left(sizeof(T))
325 {}
326
336 template<typename T>
337 void set(T *p)
338 {
339 pos = reinterpret_cast<char *>(p);
340 left = sizeof(T);
341 }
342
355 {
356 unsigned long bytes = cxx::min(cxx::min(left, dst->left), max);
357 memcpy(dst->pos, pos, bytes);
358 left -= bytes;
359 pos += bytes;
360 dst->left -= bytes;
361 dst->pos += bytes;
362 return bytes;
363 }
364
376 {
377 unsigned long b = cxx::min(left, bytes);
378 left -= b;
379 pos += b;
380 return b;
381 }
382
388 bool done() const
389 { return left == 0; }
390};
391
392class Request_processor;
393
398{
408
411
412 // The error code
413 Error error;
414
422 : proc(proc), error(e)
423 {}
424
430 char const *message() const
431 {
432 static char const *const err[] =
433 {
434 [Bad_address] = "Descriptor address cannot be translated",
435 [Bad_rights] = "Insufficient memory access rights",
436 [Bad_flags] = "Invalid descriptor flags",
437 [Bad_next] = "The descriptor's `next` index is invalid",
438 [Bad_size] = "Invalid size of the memory block"
439 };
440
441 if (error >= (sizeof(err) / sizeof(err[0])) || !err[error])
442 return "Unknown error";
443
444 return err[error];
445 }
446};
447
448
473{
474private:
476 Virtqueue::Desc const *_table;
477
479 Virtqueue::Desc _current;
480
482 l4_uint16_t _num;
483
484public:
500 template<typename DESC_MAN, typename ...ARGS>
501 void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
502 {
503 _current = cxx::access_once(request.desc());
504
505 if (_current.flags.indirect())
506 {
507 dm->load_desc(_current, this, &_table);
508 _num = _current.len / sizeof(Virtqueue::Desc);
509 if (L4_UNLIKELY(!_num))
511
512 _current = cxx::access_once(_table);
513 }
514 else
515 {
516 _table = ring->desc(0);
517 _num = ring->num();
518 }
519
520 dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
521 }
522
533 template<typename DESC_MAN, typename ...ARGS>
534 Virtqueue::Request const &start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
535 {
536 start(dm, request.ring, request, cxx::forward<ARGS>(args)...);
537 return request;
538 }
539
546 { return _current.flags; }
547
553 bool has_more() const
554 { return _current.flags.next(); }
555
569 template<typename DESC_MAN, typename ...ARGS>
570 bool next(DESC_MAN *dm, ARGS... args)
571 {
572 if (!_current.flags.next())
573 return false;
574
575 if (L4_UNLIKELY(_current.next >= _num))
577
578 _current = cxx::access_once(_table + _current.next);
579
580 if (0) // we ignore this for performance reasons
581 if (L4_UNLIKELY(_current.flags.indirect()))
583
584 // must throw an exception in case of a bad descriptor
585 dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
586 return true;
587 }
588};
589
590}
591}
Encapsulate the state for processing a VIRTIO request.
Definition virtio:473
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
Definition virtio:570
Virtqueue::Desc::Flags current_flags() const
Get the flags of the currently processed descriptor.
Definition virtio:545
Virtqueue::Request const & start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
Start processing a new request.
Definition virtio:534
bool has_more() const
Are there more chained descriptors?
Definition virtio:553
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Definition virtio:501
VIRTIO request, essentially a descriptor from the available ring.
Definition virtio:94
Desc const * desc() const
Definition virtio:112
Head_desc()
Make invalid (NULL) request.
Definition virtio:102
Virtqueue implementation for the device.
Definition virtio:88
bool desc_avail() const
Test for available descriptors.
Definition virtio:175
void enable_notify()
Clear the 'no notify' flag for this queue.
Definition virtio:284
void consumed(ITER const &begin, ITER const &end)
Put multiple descriptors into the used ring.
Definition virtio:213
Desc const * desc(unsigned idx) const
Get a descriptor from the descriptor list.
Definition virtio:298
Request next_avail()
Get the next available descriptor from the available ring.
Definition virtio:136
void finish(ITER const &begin, ITER const &end, QUEUE_OBSERVER *o)
Add a range of descriptors to the used ring, and notify an observer once.
Definition virtio:262
void disable_notify()
Set the 'no notify' flag for this queue.
Definition virtio:273
void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len=0)
Add a descriptor to the used ring, and notify an observer.
Definition virtio:240
void rewind_avail(Head_desc const &d)
Return unfinished descriptors to the available ring, i.e.
Definition virtio:160
void consumed(Head_desc const &r, l4_uint32_t len=0)
Put the given descriptor into the used ring.
Definition virtio:190
l4_uint16_t ring[]
array of available descriptor indexes.
Definition virtqueue:148
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
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
Used * _used
pointer to used ring.
Definition virtqueue:199
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
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
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
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:275
#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
T access_once(T const *a)
Read the value at an address at most once.
Definition utils:40
String.
Exception used by Queue to indicate descriptor errors.
Definition virtio:398
Request_processor const * proc
The processor that triggered the exception.
Definition virtio:410
Error
The error code.
Definition virtio:401
@ Bad_rights
Missing access rights on memory.
Definition virtio:403
@ Bad_address
Address cannot be translated.
Definition virtio:402
@ Bad_flags
Invalid combination of descriptor flags.
Definition virtio:404
@ Bad_next
Invalid next index.
Definition virtio:405
@ Bad_size
Invalid size of memory block.
Definition virtio:406
char const * message() const
Get a human readable description of the error code.
Definition virtio:430
Bad_descriptor(Request_processor const *proc, Error e)
Make a bad descriptor exception.
Definition virtio:421
Abstract data buffer.
Definition virtio:307
void set(T *p)
Set buffer for object p.
Definition virtio:337
l4_uint32_t copy_to(Data_buffer *dst, l4_uint32_t max=UINT_MAX)
Copy contents from this buffer to the destination buffer.
Definition virtio:354
l4_uint32_t left
Bytes left in buffer.
Definition virtio:309
char * pos
Current buffer position.
Definition virtio:308
l4_uint32_t skip(l4_uint32_t bytes)
Skip given number of bytes in this buffer.
Definition virtio:375
bool done() const
Check if there are no more bytes left in the buffer.
Definition virtio:388
Data_buffer(T *p)
Create buffer for object p.
Definition virtio:323
Type for device feature bitmap.
Definition virtio:67
l4_uint32_t raw
The raw value of the features bitmap.
Definition virtio:68
constexpr ring_indirect_desc_bfm_t::Val ring_indirect_desc() const
Get the ring_indirect_desc bits ( 28 to 28 ) of raw.
Definition virtio:74
constexpr ring_event_idx_bfm_t::Val ring_event_idx() const
Get the ring_event_idx bits ( 29 to 29 ) of raw.
Definition virtio:75
Dev_features(l4_uint32_t v)
Make Features from a raw bitmap.
Definition virtio:72
Type of the device status register.
Definition virtio:33
constexpr failed_bfm_t::Val failed() const
Get the failed bits ( 7 to 7 ) of raw.
Definition virtio:46
constexpr device_needs_reset_bfm_t::Val device_needs_reset() const
Get the device_needs_reset bits ( 6 to 6 ) of raw.
Definition virtio:45
bool running() const
Check if the device is in running state.
Definition virtio:57
constexpr driver_ok_bfm_t::Val driver_ok() const
Get the driver_ok bits ( 2 to 2 ) of raw.
Definition virtio:42
constexpr acked_bfm_t::Val acked() const
Get the acked bits ( 0 to 0 ) of raw.
Definition virtio:40
Dev_status(l4_uint32_t v)
Make Status from raw value.
Definition virtio:38
constexpr features_ok_bfm_t::Val features_ok() const
Get the features_ok bits ( 3 to 3 ) of raw.
Definition virtio:43
constexpr driver_bfm_t::Val driver() const
Get the driver bits ( 1 to 1 ) of raw.
Definition virtio:41
constexpr fail_state_bfm_t::Val fail_state() const
Get the fail_state bits ( 6 to 7 ) of raw.
Definition virtio:44
unsigned char raw
Raw value of the VIRTIO device status register.
Definition virtio:34
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 indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw.
Definition virtqueue:105
constexpr no_notify_bfm_t::Val no_notify() const
Get the no_notify bits ( 0 to 0 ) of raw.
Definition virtqueue:188
Type of an element of the used ring.
Definition virtqueue:155