L4Re - L4 Runtime Environment
virtio
1 // vi:ft=cpp
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 
20 #pragma once
21 
22 #include <l4/sys/types.h>
23 #include <l4/cxx/bitfield>
24 #include <l4/cxx/minmax>
25 #include <l4/cxx/utils>
26 
27 #include <limits.h>
28 #include <string.h>
29 #include <stdio.h>
30 
31 #include "../virtqueue"
32 
38 namespace L4virtio {
39 namespace Svr {
40 
44 struct Dev_status
45 {
46  unsigned char raw;
47  Dev_status() = default;
48 
50  explicit Dev_status(l4_uint32_t v) : raw(v) {}
51 
52  CXX_BITFIELD_MEMBER( 0, 0, acked, raw);
53  CXX_BITFIELD_MEMBER( 1, 1, driver, raw);
54  CXX_BITFIELD_MEMBER( 2, 2, driver_ok, raw);
55  CXX_BITFIELD_MEMBER( 3, 3, features_ok, raw);
56  CXX_BITFIELD_MEMBER( 7, 7, failed, raw);
57 
66  bool running() const
67  {
68  return (raw == 0xf);
69  }
70 };
71 
76 {
78  Dev_features() = default;
79 
81  explicit Dev_features(l4_uint32_t v) : raw(v) {}
82 
83  CXX_BITFIELD_MEMBER(28, 28, ring_indirect_desc, raw);
84  CXX_BITFIELD_MEMBER(29, 29, ring_event_idx, raw);
85 };
86 
87 
95 {
96 public:
100  class Head_desc
101  {
102  friend class Virtqueue;
103  private:
104  Virtqueue::Desc const *_d;
105  Head_desc(Virtqueue *r, unsigned i) : _d(r->desc(i)) {}
106 
107  struct Null_ptr_check;
108 
109  public:
111  Head_desc() : _d(0) {}
112 
114  bool valid() const { return _d; }
115 
117  operator Null_ptr_check const * () const
118  { return reinterpret_cast<Null_ptr_check const *>(_d); }
119 
121  Desc const *desc() const
122  { return _d; }
123  };
124 
125  struct Request : Head_desc
126  {
127  Virtqueue *ring;
128  Request() = default;
129  private:
130  friend class Virtqueue;
131  Request(Virtqueue *r, unsigned i) : Head_desc(r, i), ring(r) {}
132  };
133 
134 
144  Request next_avail()
145  {
146  if (L4_LIKELY(_current_avail != _avail->idx))
147  {
148  rmb();
149  unsigned head = _current_avail & _idx_mask;
150  ++_current_avail;
151  return Request(this, _avail->ring[head]);
152  }
153  return Request();
154  }
155 
161  bool desc_avail() const
162  {
163  return _current_avail != _avail->idx;
164  }
165 
173  void consumed(Head_desc const &r, l4_uint32_t len = 0)
174  {
175  l4_uint16_t i = _used->idx & _idx_mask;
176  _used->ring[i] = Used_elem(r._d - _desc, len);
177  wmb();
178  ++_used->idx;
179  }
180 
181  template<typename ITER>
182  void consumed(ITER const &begin, ITER const &end)
183  {
184  l4_uint16_t added = 0;
185  l4_uint16_t idx = _used->idx;
186 
187  for (auto elem = begin ; elem != end; ++elem, ++added)
188  _used->ring[(idx + added) & _idx_mask]
189  = Used_elem(elem->first._d - _desc, elem->second);
190 
191  wmb();
192  _used->idx += added;
193  }
194 
195  template<typename QUEUE_OBSERVER>
196  void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len = 0)
197  {
198  consumed(d, len);
199  o->notify_queue(this);
200  d._d = 0;
201  }
202 
203  template<typename ITER, typename QUEUE_OBSERVER>
204  void finish(ITER const &begin, ITER const &end, QUEUE_OBSERVER *o)
205  {
206  consumed(begin, end);
207  o->notify_queue(this);
208  }
209 
216  {
217  if (L4_LIKELY(ready()))
218  _used->flags.no_notify() = 1;
219  }
220 
227  {
228  if (L4_LIKELY(ready()))
229  _used->flags.no_notify() = 0;
230  }
231 
238  Desc const *desc(unsigned idx) const
239  { return _desc + idx; }
240 
241 };
242 
247 {
248  char *pos;
250 
251  Data_buffer() = default;
252 
261  template<typename T>
262  explicit Data_buffer(T *p)
263  : pos(reinterpret_cast<char *>(p)), left(sizeof(T))
264  {}
265 
274  template<typename T>
275  void set(T *p)
276  {
277  pos = reinterpret_cast<char *>(p);
278  left = sizeof(T);
279  }
280 
292  {
293  unsigned long bytes = cxx::min(cxx::min(left, dst->left), max);
294  memcpy(dst->pos, pos, bytes);
295  left -= bytes;
296  pos += bytes;
297  dst->left -= bytes;
298  dst->pos += bytes;
299  return bytes;
300  }
301 
312  {
313  unsigned long b = cxx::min(left, bytes);
314  left -= b;
315  pos += b;
316  return b;
317  }
318 
323  bool done() const
324  { return left == 0; }
325 };
326 
327 class Request_processor;
328 
333 {
335  enum Error
336  {
341  Bad_size
342  };
343 
346 
347  // The error code
348  Error error;
349 
356  : proc(proc), error(e)
357  {}
358 
364  char const *message() const
365  {
366  char const *const err[] = {
367  [Bad_address] = "Descriptor address cannot be translated",
368  [Bad_rights] = "Insufficient memory access rights",
369  [Bad_flags] = "Invalid descriptor flags",
370  [Bad_next] = "The descriptor's `next` index is invalid",
371  [Bad_size] = "Invalid size of the memory block"
372  };
373 
374  if (error >= (sizeof(err) / sizeof(err[0])))
375  return "Unknown error";
376 
377  return err[error];
378  }
379 };
380 
381 
406 {
407 private:
409  Virtqueue::Desc const *_table;
410 
412  Virtqueue::Desc _current;
413 
415  l4_uint16_t _num;
416 
417 public:
433  template<typename DESC_MAN, typename ...ARGS>
434  void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
435  {
436  _current = cxx::access_once(request.desc());
437 
438  if (_current.flags.indirect())
439  {
440  dm->load_desc(_current, this, &_table);
441  _num = _current.len / sizeof(Virtqueue::Desc);
442  if (L4_UNLIKELY(!_num))
444 
445  _current = cxx::access_once(_table);
446  }
447  else
448  {
449  _table = ring->desc(0);
450  _num = ring->num();
451  }
452 
453  dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
454  }
455 
464  template<typename DESC_MAN, typename ...ARGS>
465  Virtqueue::Request const &start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
466  {
467  start(dm, request.ring, request, cxx::forward<ARGS>(args)...);
468  return request;
469  }
470 
476  { return _current.flags; }
477 
482  bool has_more() const
483  { return _current.flags.next(); }
484 
498  template<typename DESC_MAN, typename ...ARGS>
499  bool next(DESC_MAN *dm, ARGS... args)
500  {
501  if (!_current.flags.next())
502  return false;
503 
504  if (L4_UNLIKELY(_current.next >= _num))
506 
507  _current = cxx::access_once(_table + _current.next);
508 
509  if (0) // we ignore this for performance reasons
510  if (L4_UNLIKELY(_current.flags.indirect()))
512 
513  // must throw an exception in case of a bad descriptor
514  dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
515  return true;
516  }
517 };
518 
519 }
520 }
521 
l4_uint32_t raw
The raw value of the features bitmap.
Definition: virtio:77
bool has_more() const
Are there more chained descriptors ?
Definition: virtio:482
Virtqueue::Desc::Flags current_flags() const
Get the flags of the currently processed descriptor.
Definition: virtio:475
Head_desc()
Make invalid (NULL) request.
Definition: virtio:111
Descriptor in the descriptor table.
Definition: virtqueue:93
char const * message() const
Get a human readable description of the error code.
Definition: virtio:364
Virtqueue implementation for the device.
Definition: virtio:94
void disable_notify()
Set the &#39;no notify&#39; flag for this queue.
Definition: virtio:215
String.
Missing access rights on memory.
Definition: virtio:338
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition: l4int.h:38
Low-level Virtqueue.
Definition: virtqueue:87
Common L4 ABI Data Types.
l4_uint16_t next
Index of the next chained descriptor.
Definition: virtqueue:118
Address cannot be translated.
Definition: virtio:337
bool desc_avail() const
Test for available descriptors.
Definition: virtio:161
Exception used by Queue to indicate descriptor errors.
Definition: virtio:332
l4_uint32_t left
Bytes left in buffer.
Definition: virtio:249
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Definition: virtio:434
Type of the device status register.
Definition: virtio:44
void consumed(Head_desc const &r, l4_uint32_t len=0)
Put the given descriptor into the used ring.
Definition: virtio:173
Dev_features(l4_uint32_t v)
Make Features from a raw bitmap.
Definition: virtio:81
Request next_avail()
Get the next available descriptor from the available ring.
Definition: virtio:144
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:291
Encapsulate the state for processing a VIRTIO request.
Definition: virtio:405
next_bfm_t::Val next() const
Get the next bits ( 0 to 0 ) of raw .
Definition: virtqueue:108
char * pos
Current buffer position.
Definition: virtio:248
indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw .
Definition: virtqueue:112
T1 max(T1 a, T1 b)
Get the maximum of a and b.
Definition: minmax:46
Data_buffer(T *p)
Create buffer for object p.
Definition: virtio:262
driver_bfm_t::Val driver() const
Get the driver bits ( 1 to 1 ) of raw .
Definition: virtio:53
bool running() const
Check if the device is in running state.
Definition: virtio:66
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition: compiler.h:234
features_ok_bfm_t::Val features_ok() const
Get the features_ok bits ( 3 to 3 ) of raw .
Definition: virtio:55
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
Definition: virtio:499
driver_ok_bfm_t::Val driver_ok() const
Get the driver_ok bits ( 2 to 2 ) of raw .
Definition: virtio:54
Invalid combination of descriptor flags.
Definition: virtio:339
#define L4_LIKELY(x)
Expression is likely to execute.
Definition: compiler.h:233
unsigned char raw
Raw value of the VIRTIO device status register.
Definition: virtio:46
Desc const * desc(unsigned idx) const
Get a descriptor from the descriptor list.
Definition: virtio:238
void enable_notify()
Clear the &#39;no notify&#39; flag for this queue.
Definition: virtio:226
Type for descriptor flags.
Definition: virtqueue:99
failed_bfm_t::Val failed() const
Get the failed bits ( 7 to 7 ) of raw .
Definition: virtio:56
Flags flags
Descriptor flags.
Definition: virtqueue:117
Type for device feature bitmap.
Definition: virtio:75
Dev_status(l4_uint32_t v)
Make Status from raw value.
Definition: virtio:50
Error
The error code.
Definition: virtio:335
Desc const * desc() const
Definition: virtio:121
Type of an element of the used ring.
Definition: virtqueue:160
Request_processor const * proc
The processor that triggered the exception.
Definition: virtio:345
Invalid size of memory block.
Definition: virtio:341
VIRTIO request, essentially a descriptor from the available ring.
Definition: virtio:100
L4-VIRTIO Transport C++ API.
Definition: l4virtio:29
l4_uint32_t len
Length of described buffer.
Definition: virtqueue:116
acked_bfm_t::Val acked() const
Get the acked bits ( 0 to 0 ) of raw .
Definition: virtio:52
unsigned num() const
Definition: virtqueue:407
Bad_descriptor(Request_processor const *proc, Error e)
Make a bad descriptor exception.
Definition: virtio:355
l4_uint32_t skip(l4_uint32_t bytes)
Skip given number of bytes in this buffer.
Definition: virtio:311
Virtqueue::Request const & start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
Start processing a new request.
Definition: virtio:465
Abstract data buffer.
Definition: virtio:246
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition: l4int.h:40
T1 min(T1 a, T1 b)
Get the minimum of a and b.
Definition: minmax:35
bool done() const
Check if there are no more bytes left in the buffer.
Definition: virtio:323