L4Re – L4 Runtime Environment
virtio
1 // vi:ft=cpp
2 /* SPDX-License-Identifier: GPL-2.0-only or License-Ref-kk-custom */
3 /*
4  * Copyright (C) 2014-2020 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 
26 namespace L4virtio {
27 namespace Svr {
28 
32 struct Dev_status
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 {
89 public:
93  class Head_desc
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  struct Null_ptr_check;
101 
102  public:
104  Head_desc() : _d(0) {}
105 
107  bool valid() const { return _d; }
108 
110  operator Null_ptr_check const * () const
111  { return reinterpret_cast<Null_ptr_check const *>(_d); }
112 
114  Desc const *desc() const
115  { return _d; }
116  };
117 
118  struct Request : Head_desc
119  {
120  Virtqueue *ring;
121  Request() = default;
122  private:
123  friend class Virtqueue;
124  Request(Virtqueue *r, unsigned i) : Head_desc(r, i), ring(r) {}
125  };
126 
127 
137  Request next_avail()
138  {
140  {
141  rmb();
142  unsigned head = _current_avail & _idx_mask;
143  ++_current_avail;
144  return Request(this, _avail->ring[head]);
145  }
146  return Request();
147  }
148 
154  bool desc_avail() const
155  {
156  return _current_avail != _avail->idx;
157  }
158 
166  void consumed(Head_desc const &r, l4_uint32_t len = 0)
167  {
169  _used->ring[i] = Used_elem(r._d - _desc, len);
170  wmb();
171  ++_used->idx;
172  }
173 
174  template<typename ITER>
175  void consumed(ITER const &begin, ITER const &end)
176  {
177  l4_uint16_t added = 0;
178  l4_uint16_t idx = _used->idx;
179 
180  for (auto elem = begin ; elem != end; ++elem, ++added)
181  _used->ring[(idx + added) & _idx_mask]
182  = Used_elem(elem->first._d - _desc, elem->second);
183 
184  wmb();
185  _used->idx += added;
186  }
187 
188  template<typename QUEUE_OBSERVER>
189  void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len = 0)
190  {
191  consumed(d, len);
192  o->notify_queue(this);
193  d._d = 0;
194  }
195 
196  template<typename ITER, typename QUEUE_OBSERVER>
197  void finish(ITER const &begin, ITER const &end, QUEUE_OBSERVER *o)
198  {
199  consumed(begin, end);
200  o->notify_queue(this);
201  }
202 
209  {
210  if (L4_LIKELY(ready()))
211  _used->flags.no_notify() = 1;
212  }
213 
220  {
221  if (L4_LIKELY(ready()))
222  _used->flags.no_notify() = 0;
223  }
224 
231  Desc const *desc(unsigned idx) const
232  { return _desc + idx; }
233 
234 };
235 
240 {
241  char *pos;
243 
244  Data_buffer() = default;
245 
254  template<typename T>
255  explicit Data_buffer(T *p)
256  : pos(reinterpret_cast<char *>(p)), left(sizeof(T))
257  {}
258 
267  template<typename T>
268  void set(T *p)
269  {
270  pos = reinterpret_cast<char *>(p);
271  left = sizeof(T);
272  }
273 
285  {
286  unsigned long bytes = cxx::min(cxx::min(left, dst->left), max);
287  memcpy(dst->pos, pos, bytes);
288  left -= bytes;
289  pos += bytes;
290  dst->left -= bytes;
291  dst->pos += bytes;
292  return bytes;
293  }
294 
305  {
306  unsigned long b = cxx::min(left, bytes);
307  left -= b;
308  pos += b;
309  return b;
310  }
311 
316  bool done() const
317  { return left == 0; }
318 };
319 
320 class Request_processor;
321 
326 {
328  enum Error
329  {
334  Bad_size
335  };
336 
339 
340  // The error code
341  Error error;
342 
349  : proc(proc), error(e)
350  {}
351 
357  char const *message() const
358  {
359  char const *const err[] = {
360  [Bad_address] = "Descriptor address cannot be translated",
361  [Bad_rights] = "Insufficient memory access rights",
362  [Bad_flags] = "Invalid descriptor flags",
363  [Bad_next] = "The descriptor's `next` index is invalid",
364  [Bad_size] = "Invalid size of the memory block"
365  };
366 
367  if (error >= (sizeof(err) / sizeof(err[0])))
368  return "Unknown error";
369 
370  return err[error];
371  }
372 };
373 
374 
399 {
400 private:
402  Virtqueue::Desc const *_table;
403 
405  Virtqueue::Desc _current;
406 
408  l4_uint16_t _num;
409 
410 public:
426  template<typename DESC_MAN, typename ...ARGS>
427  void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
428  {
429  _current = cxx::access_once(request.desc());
430 
431  if (_current.flags.indirect())
432  {
433  dm->load_desc(_current, this, &_table);
434  _num = _current.len / sizeof(Virtqueue::Desc);
435  if (L4_UNLIKELY(!_num))
437 
438  _current = cxx::access_once(_table);
439  }
440  else
441  {
442  _table = ring->desc(0);
443  _num = ring->num();
444  }
445 
446  dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
447  }
448 
457  template<typename DESC_MAN, typename ...ARGS>
458  Virtqueue::Request const &start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
459  {
460  start(dm, request.ring, request, cxx::forward<ARGS>(args)...);
461  return request;
462  }
463 
469  { return _current.flags; }
470 
475  bool has_more() const
476  { return _current.flags.next(); }
477 
491  template<typename DESC_MAN, typename ...ARGS>
492  bool next(DESC_MAN *dm, ARGS... args)
493  {
494  if (!_current.flags.next())
495  return false;
496 
497  if (L4_UNLIKELY(_current.next >= _num))
499 
500  _current = cxx::access_once(_table + _current.next);
501 
502  if (0) // we ignore this for performance reasons
503  if (L4_UNLIKELY(_current.flags.indirect()))
505 
506  // must throw an exception in case of a bad descriptor
507  dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
508  return true;
509  }
510 };
511 
512 }
513 }
Encapsulate the state for processing a VIRTIO request.
Definition: virtio:399
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
Definition: virtio:492
Virtqueue::Desc::Flags current_flags() const
Get the flags of the currently processed descriptor.
Definition: virtio:468
bool has_more() const
Are there more chained descriptors?
Definition: virtio:475
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Definition: virtio:427
Virtqueue::Request const & start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
Start processing a new request.
Definition: virtio:458
VIRTIO request, essentially a descriptor from the available ring.
Definition: virtio:94
Desc const * desc() const
Definition: virtio:114
Head_desc()
Make invalid (NULL) request.
Definition: virtio:104
Virtqueue implementation for the device.
Definition: virtio:88
bool desc_avail() const
Test for available descriptors.
Definition: virtio:154
void enable_notify()
Clear the 'no notify' flag for this queue.
Definition: virtio:219
Request next_avail()
Get the next available descriptor from the available ring.
Definition: virtio:137
Desc const * desc(unsigned idx) const
Get a descriptor from the descriptor list.
Definition: virtio:231
void disable_notify()
Set the 'no notify' flag for this queue.
Definition: virtio:208
void consumed(Head_desc const &r, l4_uint32_t len=0)
Put the given descriptor into the used ring.
Definition: virtio:166
l4_uint16_t ring[]
array of available descriptor indexes.
Definition: virtqueue:156
l4_uint16_t idx
available index written by guest
Definition: virtqueue:155
Descriptor in the descriptor table.
Definition: virtqueue:96
l4_uint16_t next
Index of the next chained descriptor.
Definition: virtqueue:120
l4_uint32_t len
Length of described buffer.
Definition: virtqueue:118
Flags flags
Descriptor flags.
Definition: virtqueue:119
Used_elem ring[]
array of used descriptors.
Definition: virtqueue:201
l4_uint16_t idx
index of the last entry in the ring.
Definition: virtqueue:200
Flags flags
flags of the used ring.
Definition: virtqueue:199
Low-level Virtqueue.
Definition: virtqueue:90
Used * _used
pointer to used ring.
Definition: virtqueue:207
bool ready() const
Test if this queue is in working state.
Definition: virtqueue:405
l4_uint16_t _idx_mask
mask used for indexing into the descriptor table and the rings.
Definition: virtqueue:216
Desc * _desc
pointer to descriptor table, NULL if queue is off.
Definition: virtqueue:205
Avail * _avail
pointer to available ring.
Definition: virtqueue:206
l4_uint16_t _current_avail
The life counter for the queue.
Definition: virtqueue:210
unsigned num() const
Definition: virtqueue:409
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition: compiler.h:238
#define L4_LIKELY(x)
Expression is likely to execute.
Definition: compiler.h:237
T1 min(T1 a, T1 b)
Get the minimum of a and b.
Definition: minmax:35
T1 max(T1 a, T1 b)
Get the maximum of a and b.
Definition: minmax:46
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
Common L4 ABI Data Types.
L4-VIRTIO Transport C++ API.
Definition: virtio-block:29
String.
Exception used by Queue to indicate descriptor errors.
Definition: virtio:326
Request_processor const * proc
The processor that triggered the exception.
Definition: virtio:338
char const * message() const
Get a human readable description of the error code.
Definition: virtio:357
Error
The error code.
Definition: virtio:329
@ Bad_rights
Missing access rights on memory.
Definition: virtio:331
@ Bad_address
Address cannot be translated.
Definition: virtio:330
@ Bad_flags
Invalid combination of descriptor flags.
Definition: virtio:332
@ Bad_next
Invalid next index.
Definition: virtio:333
@ Bad_size
Invalid size of memory block.
Definition: virtio:334
Bad_descriptor(Request_processor const *proc, Error e)
Make a bad descriptor exception.
Definition: virtio:348
Abstract data buffer.
Definition: virtio:240
void set(T *p)
Set buffer for object p.
Definition: virtio:268
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:284
l4_uint32_t left
Bytes left in buffer.
Definition: virtio:242
char * pos
Current buffer position.
Definition: virtio:241
l4_uint32_t skip(l4_uint32_t bytes)
Skip given number of bytes in this buffer.
Definition: virtio:304
bool done() const
Check if there are no more bytes left in the buffer.
Definition: virtio:316
Data_buffer(T *p)
Create buffer for object p.
Definition: virtio:255
Type for device feature bitmap.
Definition: virtio:67
l4_uint32_t raw
The raw value of the features bitmap.
Definition: virtio:68
ring_indirect_desc_bfm_t::Val ring_indirect_desc() const
Get the ring_indirect_desc bits ( 28 to 28 ) of raw.
Definition: virtio:74
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
device_needs_reset_bfm_t::Val device_needs_reset() const
Get the device_needs_reset bits ( 6 to 6 ) of raw.
Definition: virtio:45
features_ok_bfm_t::Val features_ok() const
Get the features_ok bits ( 3 to 3 ) of raw.
Definition: virtio:43
acked_bfm_t::Val acked() const
Get the acked bits ( 0 to 0 ) of raw.
Definition: virtio:40
driver_ok_bfm_t::Val driver_ok() const
Get the driver_ok bits ( 2 to 2 ) of raw.
Definition: virtio:42
bool running() const
Check if the device is in running state.
Definition: virtio:57
fail_state_bfm_t::Val fail_state() const
Get the fail_state bits ( 6 to 7 ) of raw.
Definition: virtio:44
driver_bfm_t::Val driver() const
Get the driver bits ( 1 to 1 ) of raw.
Definition: virtio:41
Dev_status(l4_uint32_t v)
Make Status from raw value.
Definition: virtio:38
failed_bfm_t::Val failed() const
Get the failed bits ( 7 to 7 ) of raw.
Definition: virtio:46
unsigned char raw
Raw value of the VIRTIO device status register.
Definition: virtio:34
Type for descriptor flags.
Definition: virtqueue:102
next_bfm_t::Val next() const
Get the next bits ( 0 to 0 ) of raw.
Definition: virtqueue:110
indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw.
Definition: virtqueue:114
no_notify_bfm_t::Val no_notify() const
Get the no_notify bits ( 0 to 0 ) of raw.
Definition: virtqueue:196
Type of an element of the used ring.
Definition: virtqueue:163