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 <string.h>
28 #include <stdio.h>
29 
30 #include "../virtqueue"
31 
37 namespace L4virtio {
38 namespace Svr {
39 
43 struct Dev_status
44 {
45  unsigned char raw;
46  Dev_status() = default;
47 
49  explicit Dev_status(l4_uint32_t v) : raw(v) {}
50 
51  CXX_BITFIELD_MEMBER( 0, 0, acked, raw);
52  CXX_BITFIELD_MEMBER( 1, 1, driver, raw);
53  CXX_BITFIELD_MEMBER( 2, 2, driver_ok, raw);
54  CXX_BITFIELD_MEMBER( 4, 4, feature_ok, raw);
55  CXX_BITFIELD_MEMBER( 7, 7, failed, raw);
56 
65  bool running() const
66  {
67  return (raw == 0xf);
68  }
69 };
70 
75 {
77  Dev_features() = default;
78 
80  explicit Dev_features(l4_uint32_t v) : raw(v) {}
81 
82  CXX_BITFIELD_MEMBER(28, 28, ring_indirect_desc, raw);
83  CXX_BITFIELD_MEMBER(29, 29, ring_event_idx, raw);
84 };
85 
86 
94 {
95 public:
99  class Head_desc
100  {
101  friend class Virtqueue;
102  private:
103  Virtqueue::Desc const *_d;
104  Head_desc(Virtqueue *r, unsigned i) : _d(r->desc(i)) {}
105 
106  struct Null_ptr_check;
107 
108  public:
110  Head_desc() : _d(0) {}
111 
113  bool valid() const { return _d; }
114 
116  operator Null_ptr_check const * () const
117  { return reinterpret_cast<Null_ptr_check const *>(_d); }
118 
120  Desc const *desc() const
121  { return _d; }
122  };
123 
124  struct Request : Head_desc
125  {
126  Virtqueue *ring;
127  Request() = default;
128  private:
129  friend class Virtqueue;
130  Request(Virtqueue *r, unsigned i) : Head_desc(r, i), ring(r) {}
131  };
132 
133 
143  Request next_avail()
144  {
145  if (L4_LIKELY(_current_avail != _avail->idx))
146  {
147  rmb();
148  unsigned head = _current_avail & _idx_mask;
149  ++_current_avail;
150  return Request(this, _avail->ring[head]);
151  }
152  return Request();
153  }
154 
160  bool desc_avail() const
161  {
162  return _current_avail != _avail->idx;
163  }
164 
172  void consumed(Head_desc const &r, l4_uint32_t len = 0)
173  {
174  l4_uint16_t i = _used->idx & _idx_mask;
175  _used->ring[i] = Used_elem(r._d - _desc, len);
176  wmb();
177  ++_used->idx;
178  }
179 
180  template<typename ITER>
181  void consumed(ITER const &begin, ITER const &end)
182  {
183  l4_uint16_t added = 0;
184  l4_uint16_t idx = _used->idx;
185 
186  for (auto elem = begin ; elem != end; ++elem, ++added)
187  _used->ring[(idx + added) & _idx_mask]
188  = Used_elem(elem->first._d - _desc, elem->second);
189 
190  wmb();
191  _used->idx += added;
192  }
193 
194  template<typename QUEUE_OBSERVER>
195  void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len = 0)
196  {
197  consumed(d, len);
198  o->notify_queue(this);
199  d._d = 0;
200  }
201 
202  template<typename ITER, typename QUEUE_OBSERVER>
203  void finish(ITER const &begin, ITER const &end, QUEUE_OBSERVER *o)
204  {
205  consumed(begin, end);
206  o->notify_queue(this);
207  }
208 
215  {
216  if (L4_LIKELY(ready()))
217  _used->flags.no_notify() = 1;
218  }
219 
226  {
227  if (L4_LIKELY(ready()))
228  _used->flags.no_notify() = 0;
229  }
230 
237  Desc const *desc(unsigned idx) const
238  { return _desc + idx; }
239 
240 };
241 
246 {
247  char *pos;
249 
250  Data_buffer() = default;
251 
260  template<typename T>
261  explicit Data_buffer(T *p)
262  : pos(reinterpret_cast<char *>(p)), left(sizeof(T))
263  {}
264 
273  template<typename T>
274  void set(T *p)
275  {
276  pos = reinterpret_cast<char *>(p);
277  left = sizeof(T);
278  }
279 
289  {
290  unsigned long bytes = cxx::min(left, dst->left);
291  memcpy(dst->pos, pos, bytes);
292  left -= bytes;
293  pos += bytes;
294  dst->left -= bytes;
295  dst->pos += bytes;
296  return bytes;
297  }
298 
309  {
310  unsigned long b = cxx::min(left, bytes);
311  left -= b;
312  pos += b;
313  return b;
314  }
315 
320  bool done() const
321  { return left == 0; }
322 };
323 
324 class Request_processor;
325 
330 {
332  enum Error
333  {
338  Bad_size
339  };
340 
343 
344  // The error code
345  Error error;
346 
353  : proc(proc), error(e)
354  {}
355 };
356 
357 
382 {
383 private:
385  Virtqueue::Desc const *_table;
386 
388  Virtqueue::Desc _current;
389 
391  l4_uint16_t _num;
392 
393 public:
403  template<typename DESC_MAN, typename ...ARGS>
404  void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
405  {
406  _current = cxx::access_once(request.desc());
407 
408  if (_current.flags.indirect())
409  {
410  dm->load_desc(_current, this, &_table);
411  _num = _current.len / sizeof(Virtqueue::Desc);
412  if (L4_UNLIKELY(!_num))
414 
415  _current = cxx::access_once(_table);
416  }
417  else
418  {
419  _table = ring->desc(0);
420  _num = ring->num();
421  }
422 
423  dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
424  }
425 
434  template<typename DESC_MAN, typename ...ARGS>
435  Virtqueue::Request const &start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
436  {
437  start(dm, request.ring, request, cxx::forward<ARGS>(args)...);
438  return request;
439  }
440 
446  { return _current.flags; }
447 
452  bool has_more() const
453  { return _current.flags.next(); }
454 
462  template<typename DESC_MAN, typename ...ARGS>
463  bool next(DESC_MAN *dm, ARGS... args)
464  {
465  if (!_current.flags.next())
466  return false;
467 
468  if (L4_UNLIKELY(_current.next >= _num))
470 
471  _current = cxx::access_once(_table + _current.next);
472 
473  if (0) // we ignore this for performance reasons
474  if (L4_UNLIKELY(_current.flags.indirect()))
476 
477  // must throw an exception in case of a bad descriptor
478  dm->load_desc(_current, this, cxx::forward<ARGS>(args)...);
479  return true;
480  }
481 };
482 
483 }
484 }
485 
l4_uint32_t raw
The raw value of the features bitmap.
Definition: virtio:76
bool has_more() const
Are there more chained descriptors ?
Definition: virtio:452
Virtqueue::Desc::Flags current_flags() const
Get the flags of the currently processed descriptor.
Definition: virtio:445
Head_desc()
Make invalid (NULL) request.
Definition: virtio:110
Descriptor in the descriptor table.
Definition: virtqueue:93
Virtqueue implementation for the device.
Definition: virtio:93
void disable_notify()
Set the &#39;no notify&#39; flag for this queue.
Definition: virtio:214
String.
Missing access rights on memory.
Definition: virtio:335
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:334
feature_ok_bfm_t::Val feature_ok() const
Get the feature_ok bits ( 4 to 4 ) of raw .
Definition: virtio:54
bool desc_avail() const
Test for available descriptors.
Definition: virtio:160
Exception used by Queue to indicate descriptor errors.
Definition: virtio:329
l4_uint32_t left
Bytes left in buffer.
Definition: virtio:248
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Definition: virtio:404
Type of the device status register.
Definition: virtio:43
void consumed(Head_desc const &r, l4_uint32_t len=0)
Put the given descriptor into the used ring.
Definition: virtio:172
Dev_features(l4_uint32_t v)
Make Features from a raw bitmap.
Definition: virtio:80
Request next_avail()
Get the next available descriptor from the available ring.
Definition: virtio:143
Encapsulate the state for processing a VIRTIO request.
Definition: virtio:381
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:247
indirect_bfm_t::Val indirect() const
Get the indirect bits ( 2 to 2 ) of raw .
Definition: virtqueue:112
Data_buffer(T *p)
Create buffer for object p.
Definition: virtio:261
l4_uint32_t copy_to(Data_buffer *dst)
Copy contents from this buffer to the destination buffer.
Definition: virtio:288
driver_bfm_t::Val driver() const
Get the driver bits ( 1 to 1 ) of raw .
Definition: virtio:52
bool running() const
Check if the device is in running state.
Definition: virtio:65
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition: compiler.h:234
bool next(DESC_MAN *dm, ARGS... args)
Switch to the next descriptor in a descriptor chain.
Definition: virtio:463
driver_ok_bfm_t::Val driver_ok() const
Get the driver_ok bits ( 2 to 2 ) of raw .
Definition: virtio:53
Invalid combination of descriptor flags.
Definition: virtio:336
#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:45
Desc const * desc(unsigned idx) const
Get a descriptor from the descriptor list.
Definition: virtio:237
void enable_notify()
Clear the &#39;no notify&#39; flag for this queue.
Definition: virtio:225
Type for descriptor flags.
Definition: virtqueue:99
failed_bfm_t::Val failed() const
Get the failed bits ( 7 to 7 ) of raw .
Definition: virtio:55
Flags flags
Descriptor flags.
Definition: virtqueue:117
Type for device feature bitmap.
Definition: virtio:74
Dev_status(l4_uint32_t v)
Make Status from raw value.
Definition: virtio:49
Error
The error code.
Definition: virtio:332
Desc const * desc() const
Definition: virtio:120
Type of an element of the used ring.
Definition: virtqueue:160
Request_processor const * proc
The processor that triggered the exception.
Definition: virtio:342
Invalid size of memory block.
Definition: virtio:338
VIRTIO request, essentially a descriptor from the available ring.
Definition: virtio:99
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:51
unsigned num() const
Definition: virtqueue:407
Bad_descriptor(Request_processor const *proc, Error e)
Make a bad descriptor exception.
Definition: virtio:352
l4_uint32_t skip(l4_uint32_t bytes)
Skip given number of bytes in this buffer.
Definition: virtio:308
Virtqueue::Request const & start(DESC_MAN *dm, Virtqueue::Request const &request, ARGS... args)
Start processing a new request.
Definition: virtio:435
Abstract data buffer.
Definition: virtio:245
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:320