L4Re - L4 Runtime Environment
l4virtio
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 #pragma once
19 
20 #include <limits.h>
21 
22 #include <l4/re/dataspace>
23 #include <l4/re/env>
24 #include <l4/re/error_helper>
25 #include <l4/re/rm>
26 #include <l4/re/util/cap_alloc>
27 #include <l4/re/util/unique_cap>
28 
29 #include <l4/sys/types.h>
30 #include <l4/re/util/meta>
31 
32 #include <l4/cxx/bitfield>
33 #include <l4/cxx/utils>
34 #include <l4/cxx/unique_ptr>
35 
36 #include <l4/sys/cxx/ipc_legacy>
37 
38 #include "../l4virtio"
39 #include "virtio"
40 
44 namespace L4virtio {
45 namespace Svr {
46 
57 {
58 public:
59  typedef Dev_status Status;
60  typedef Dev_features Features;
61 
62 private:
63  typedef L4Re::Rm::Unique_region< l4virtio_config_hdr_t*> Cfg_region;
65 
66  l4_uint32_t _vendor, _device, _qoffset, _nqueues;
67  l4_uint32_t _host_features[sizeof(l4virtio_config_hdr_t::dev_features_map)
68  / sizeof(l4_uint32_t)];
69  Cfg_cap _ds;
70  Cfg_region _config;
71  l4_addr_t _ds_offset = 0;
72 
73  Status _status; // status shadow, can be trusted by the device model
74 
75  static l4_uint32_t align(l4_uint32_t x)
76  { return (x + 0xfU) & ~0xfU; }
77 
78 protected:
79  void volatile *get_priv_config() const
80  {
81  return l4virtio_device_config(_config.get());
82  }
83 
84 public:
85 
98  unsigned cfg_size, l4_uint32_t num_queues = 0)
99  : _vendor(vendor), _device(device),
100  _qoffset(0x100 + align(cfg_size)),
101  _nqueues(num_queues)
102  {
103  using L4Re::Dataspace;
104  using L4Re::chkcap;
105  using L4Re::chksys;
106 
107  //if (_cfg_offset + align(cfg_size) >= L4_PAGESIZE)
108  // hm what to do
109 
110  if (sizeof(l4virtio_config_queue_t) * _nqueues + _qoffset > L4_PAGESIZE)
111  {
112  // too many queues does not fit into our page
113  _qoffset = 0;
114  _nqueues = 0;
115  }
116 
118  Cfg_cap cfg = chkcap(L4Re::Util::make_unique_cap<Dataspace>());
119  chksys(L4Re::Env::env()->mem_alloc()->alloc(L4_PAGESIZE, cfg.get()));
120  chksys(L4Re::Env::env()->rm()->attach(&_config, L4_PAGESIZE,
122  L4::Ipc::make_cap_rw(cfg.get())));
123  _ds = cxx::move(cfg);
124  _config->generation = 0;
125  memset(_config->driver_features_map, 0, sizeof (_config->driver_features_map));
126  memset(_host_features, 0, sizeof(_host_features));
127  _host_features[1] = 1; // virtio 1
128  reset_hdr();
129  }
130 
131  void set_host_feature(unsigned feature)
132  { l4virtio_set_feature(_host_features, feature); }
133 
134  void clear_host_feature(unsigned feature)
135  { l4virtio_clear_feature(_host_features, feature); }
136 
137  bool get_host_feature(unsigned feature)
138  { return l4virtio_get_feature(_host_features, feature); }
139 
140  l4_uint32_t &host_features(unsigned idx)
141  { return _host_features[idx]; }
142 
143  l4_uint32_t host_features(unsigned idx) const
144  { return _host_features[idx]; }
145 
157  l4_uint32_t guest_features(unsigned idx) const
158  { return _config->driver_features_map[idx]; }
159 
171  l4_uint32_t negotiated_features(unsigned idx) const
172  { return _config->driver_features_map[idx] & _host_features[idx]; }
173 
181  Status status() const { return _status; }
182 
190  {
191  return hdr()->cmd;
192  }
193 
200  void reset_cmd()
201  {
202  const_cast<l4_uint32_t volatile &>(hdr()->cmd) = 0;
203  }
204 
212  void set_status(Status status)
213  {
214  _status = status;
215  const_cast<l4_uint32_t volatile &>(hdr()->status) = status.raw;
216  }
217 
224  void set_failed()
225  {
226  _status.failed() = 1;
227  const_cast<l4_uint32_t volatile &>(hdr()->status) = _status.raw;
228  }
229 
235  {
236  if (sizeof(l4virtio_config_queue_t) * num_queues + _qoffset > L4_PAGESIZE)
237  // too many queues does not fit into our page
238  return false;
239 
240  _nqueues = num_queues;
241  reset_hdr(true);
242  return true;
243  }
244 
251  l4virtio_config_queue_t volatile const *qconfig(unsigned index) const
252  {
253  if (L4_UNLIKELY(_qoffset < sizeof (l4virtio_config_hdr_t)))
254  return 0;
255 
256  if (L4_UNLIKELY(index >= _nqueues))
257  return 0;
258 
259  return reinterpret_cast<l4virtio_config_queue_t const *>
260  (reinterpret_cast<char *>(_config.get()) + _qoffset) + index;
261  }
262 
266  void reset_hdr(bool inc_generation = false) const
267  {
268  _config->magic = L4VIRTIO_MAGIC;
269  _config->version = 2;
270  _config->device = _device;
271  _config->vendor = _vendor;
272  _config->status = 0;
273  _config->irq_status = 0;
274  _config->num_queues = _nqueues;
275  _config->queues_offset = _qoffset;
276 
277  memcpy(_config->dev_features_map, _host_features,
278  sizeof(_config->dev_features_map));
279  wmb();
280  if (inc_generation)
281  ++_config->generation;
282 
283  }
284 
293  bool reset_queue(unsigned index, unsigned num_max,
294  bool inc_generation = false) const
295  {
296  l4virtio_config_queue_t volatile *qc;
297  // this function is allowed to write to the device config
298  qc = const_cast<l4virtio_config_queue_t volatile *>(qconfig(index));
299  if (L4_UNLIKELY(qc == 0))
300  return false;
301 
302  qc->num_max = num_max;
303  qc->num = 0;
304  qc->ready = 0;
305  wmb();
306  if (inc_generation)
307  ++_config->generation;
308 
309  return true;
310  }
311 
316  l4virtio_config_hdr_t const volatile *hdr() const
317  { return _config.get(); }
318 
323  L4::Cap<L4Re::Dataspace> ds() const { return _ds.get(); }
324 
330  { return _ds_offset; }
331 };
332 
333 
334 template<typename PRIV_CONFIG>
335 class Dev_config_t : public Dev_config
336 {
337 public:
339  typedef PRIV_CONFIG Priv_config;
340 
351  Dev_config_t(l4_uint32_t vendor, l4_uint32_t device,
352  l4_uint32_t num_queues = 0)
353  : Dev_config(vendor, device, sizeof(PRIV_CONFIG), num_queues)
354  {}
355 
365  Priv_config volatile *priv_config() const
366  {
367  return static_cast<Priv_config volatile *>(get_priv_config());
368  }
369 
370 };
371 
372 struct No_custom_data {};
373 
379 template <typename DATA>
380 class Driver_mem_region_t : public DATA
381 {
382 public:
383  struct Flags
384  {
385  l4_uint32_t raw;
386  CXX_BITFIELD_MEMBER(0, 0, rw, raw);
387  };
388 
389 private:
392 
393  l4_uint64_t _drv_base;
394  l4_uint64_t _trans_offset;
395  l4_umword_t _size;
396  Flags _flags;
397 
398  Ds_cap _ds;
399  l4_addr_t _ds_offset;
400 
402  L4Re::Rm::Unique_region<l4_addr_t> _local_base;
403 
404  template<typename T>
405  T _local(l4_uint64_t addr) const
406  {
407  return (T)(addr - _trans_offset);
408  }
409 
410 public:
412  Driver_mem_region_t() : _size(0) {}
413 
426  l4_addr_t offset, Ds_cap &&ds)
427  : _drv_base(l4_trunc_page(drv_base)), _size(0),
428  _ds_offset(l4_trunc_page(offset))
429  {
430  using L4Re::chksys;
431  using L4Re::Env;
432 
434  // Sometimes we work with dataspaces that do not implement all dataspace
435  // methods and return an error instead. An example of such a dataspace is
436  // io's Vi::System_bus. We detect this case when the info method returns
437  // -L4_ENOSYS and simply assume the dataspace is good for us.
438  long err = ds->info(&ds_info);
439  if (err >= 0)
440  {
441  l4_addr_t ds_size = l4_round_page(ds_info.size);
442 
443  if (ds_size < L4_PAGESIZE)
444  chksys(-L4_EINVAL, "DS too small");
445 
446  if (_ds_offset >= ds_size)
447  chksys(-L4_ERANGE, "offset larger than DS size");
448 
449  size = l4_round_page(size);
450  if (size > ds_size)
451  chksys(-L4_EINVAL, "size larger than DS size");
452 
453  if (_ds_offset > ds_size - size)
454  chksys(-L4_EINVAL, "invalid offset or size");
455 
456  // overflow check
457  if ((ULLONG_MAX - size) < _drv_base)
458  chksys(-L4_EINVAL, "invalid size");
459 
460  _flags.rw() = ds_info.flags & L4Re::Dataspace::Map_rw;
461  }
462  else if (err == -L4_ENOSYS)
463  {
464  _flags.rw() = true;
465  }
466  else
467  {
468  chksys(err, "getting data-space infos");
469  }
470 
471  // use a big alignment to save PT/TLB entries and kernel memory resources!
472  chksys(Env::env()->rm()->attach(&_local_base, size,
473  L4Re::Rm::Search_addr | (_flags.rw() ? 0 : L4Re::Rm::Read_only),
474  L4::Ipc::make_cap(ds.get(), _flags.rw()
476  : L4_CAP_FPAGE_RO),
477  _ds_offset, L4_SUPERPAGESHIFT));
478 
479  _size = size;
480  _ds = cxx::move(ds);
481  _trans_offset = _drv_base - _local_base.get();
482  }
483 
485  bool is_writable() const { return _flags.rw(); }
486 
488  Flags flags() const { return _flags; }
489 
491  bool empty() const
492  { return _size == 0; }
493 
495  l4_uint64_t drv_base() const { return _drv_base; }
496 
498  void *local_base() const { return (void*)_local_base.get(); }
499 
501  l4_umword_t size() const { return _size; }
502 
504  l4_addr_t ds_offset() const { return _ds_offset; }
505 
507  L4::Cap<L4Re::Dataspace> ds() const { return _ds.get(); }
508 
516  bool contains(l4_uint64_t base, l4_umword_t size) const
517  {
518  if (base < _drv_base)
519  return false;
520 
521  if (base > _drv_base + _size - 1)
522  return false;
523 
524  if (size > _size)
525  return false;
526 
527  if (base - _drv_base > _size - size)
528  return false;
529 
530  return true;
531  }
532 
539  template<typename T>
540  T *local(Ptr<T> p) const
541  { return _local<T*>(p.get()); }
542 };
543 
545 
552 template <typename DATA>
554 {
555 public:
557 
558 private:
559  cxx::unique_ptr<Mem_region[]> _l;
560  unsigned _max;
561  unsigned _free;
562 
563 public:
566 
568  Driver_mem_list_t() : _max(0), _free(0) {}
569 
574  void init(unsigned max)
575  {
576  _l = cxx::make_unique<Driver_mem_region_t<DATA>[]>(max);
577  _max = max;
578  _free = 0;
579  }
580 
582  bool full() const
583  { return _free == _max; }
584 
593  Mem_region const *add(l4_uint64_t drv_base, l4_umword_t size,
594  l4_addr_t offset, Ds_cap &&ds)
595  {
596  if (full())
598 
599  _l[_free++] = Mem_region(drv_base, size, offset, cxx::move(ds));
600  return &_l[_free - 1];
601  }
602 
607  void remove(Mem_region const *r)
608  {
609  if (r < &_l[0] || r >= &_l[_free])
611 
612  unsigned idx = r - &_l[0];
613 
614  for (unsigned i = idx + 1; i < _free - 1; ++i)
615  _l[i] = cxx::move(_l[i + 1]);
616 
617  _l[--_free] = Mem_region();
618  }
619 
627  Mem_region *find(l4_uint64_t base, l4_umword_t size) const
628  {
629  return _find(base, size);
630  }
631 
641  void load_desc(Virtqueue::Desc const &desc, Request_processor const *p,
642  Virtqueue::Desc const **table) const
643  {
644  Mem_region const *r = find(desc.addr.get(), desc.len);
645  if (L4_UNLIKELY(!r))
647 
648  *table = static_cast<Virtqueue::Desc const *>(r->local(desc.addr));
649  }
650 
661  void load_desc(Virtqueue::Desc const &desc, Request_processor const *p,
662  Mem_region const **data) const
663  {
664  Mem_region const *r = find(desc.addr.get(), desc.len);
665  if (L4_UNLIKELY(!r))
667 
668  *data = r;
669  }
670 
687  template<typename ARG>
688  void load_desc(Virtqueue::Desc const &desc, Request_processor const *p,
689  ARG *data) const
690  {
691  Mem_region *r = find(desc.addr.get(), desc.len);
692  if (L4_UNLIKELY(!r))
694 
695  *data = ARG(r, desc, p);
696  }
697 
698 private:
699  Mem_region *_find(l4_uint64_t base, l4_umword_t size) const
700  {
701  for (unsigned i = 0; i < _free; ++i)
702  if (_l[i].contains(base, size))
703  return &_l[i];
704  return 0;
705  }
706 
707 
708 };
709 
711 
730 template<typename DATA>
731 class Device_t
732 {
733 public:
735 
736 protected:
737  Mem_list _mem_info;
738 
739 private:
740  Dev_config *_device_config;
741 
742 public:
743  L4_RPC_LEGACY_DISPATCH(L4virtio::Device);
744  template<typename IOS> int virtio_dispatch(unsigned r, IOS &ios)
745  { return dispatch(r, ios); }
746 
748  virtual void reset() = 0;
749 
751  virtual bool check_features()
752  { return true; }
753 
755  virtual bool check_queues() = 0;
756 
758  virtual int reconfig_queue(unsigned idx) = 0;
759 
762  { L4Re::chksys(-L4_ENOSYS, "Legacy single IRQ interface not implemented."); }
763 
766  {
767  L4Re::chksys(-L4_ENOSYS, "Legacy single IRQ interface not implemented.");
768  return L4::Cap<L4::Irq>();
769  }
770 
777  virtual void register_driver_irq(unsigned idx)
778  {
779  if (idx != 0)
780  L4Re::chksys(-L4_ENOSYS, "Multi IRQ interface not implemented.");
781 
782  register_single_driver_irq();
783  }
784 
791  virtual L4::Cap<L4::Irq> device_notify_irq(unsigned idx)
792  {
793  if (idx != 0)
794  L4Re::chksys(-L4_ENOSYS, "Multi IRQ interface not implemented.");
795 
796  return device_notify_irq();
797  }
798 
800  virtual unsigned num_events_supported() const
801  { return 1; }
802 
803  virtual L4::Ipc_svr::Server_iface *server_iface() const = 0;
804 
808  Device_t(Dev_config *dev_config)
809  : _device_config(dev_config)
810  {}
811 
815  Mem_list const *mem_info() const
816  { return &_mem_info; };
817 
818  long op_set_status(L4virtio::Device::Rights, unsigned status)
819  { return _set_status(status); }
820 
821  long op_config_queue(L4virtio::Device::Rights, unsigned queue)
822  {
823  Dev_config::Status status = _device_config->status();
824  if (status.failed())
825  return -L4_EIO;
826 
827  if (!status.acked() || !status.driver())
828  return -L4_EIO;
829 
830  return reconfig_queue(queue);
831  }
832 
833  long op_register_ds(L4virtio::Device::Rights,
834  L4::Ipc::Snd_fpage ds_cap_fp, l4_uint64_t ds_base,
835  l4_umword_t offset, l4_umword_t sz)
836  {
837  printf("Registering dataspace from 0x%llx with %lu KiB, offset 0x%lx\n",
838  ds_base, sz >> 10, offset);
839 
840  _check_n_init_shm(ds_cap_fp, ds_base, sz, offset);
841 
842  return 0;
843  }
844 
845  long op_register_iface(L4virtio::Device::Rights,
846  L4::Ipc::Snd_fpage irq_cap_fp,
849  {
850  // If a dataspace with offset is used, the old-style registration
851  // interface cannot be supported.
852  if (_device_config->ds_offset() != 0)
853  return -L4_ENOSYS;
854 
855  if (!irq_cap_fp.cap_received())
856  return -L4_EINVAL;
857 
858  register_single_driver_irq();
859 
860  printf("register client: host IRQ: %lx config DS: %lx\n",
861  device_notify_irq().cap(), _device_config->ds().cap());
862 
863  host_irq = L4::Ipc::make_cap(device_notify_irq(), L4_CAP_FPAGE_RO);
864  config_ds = L4::Ipc::make_cap(_device_config->ds(), L4_CAP_FPAGE_RW);
865  return 0;
866  }
867 
868  long op_device_config(L4virtio::Device::Rights,
871  {
872  printf("register client: host IRQ: %lx config DS: %lx\n",
873  device_notify_irq().cap(), _device_config->ds().cap());
874 
875  config_ds = L4::Ipc::make_cap(_device_config->ds(), L4_CAP_FPAGE_RW);
876  ds_offset = _device_config->ds_offset();
877  return 0;
878  }
879 
880  long op_device_notification_irq(L4virtio::Device::Rights,
881  unsigned idx,
883  {
884  auto cap = device_notify_irq(idx);
885 
886  if (!cap.is_valid())
887  return -L4_EINVAL;
888 
890  return L4_EOK;
891  }
892 
893  int op_bind(L4::Icu::Rights, l4_umword_t idx, L4::Ipc::Snd_fpage irq_cap_fp)
894  {
895  if (idx >= num_events_supported())
896  return -L4_ERANGE;
897 
898  if (!irq_cap_fp.cap_received())
899  return -L4_EINVAL;
900 
901  register_driver_irq(idx);
902 
903  return L4_EOK;
904  }
905 
906  int op_unbind(L4::Icu::Rights, l4_umword_t, L4::Ipc::Snd_fpage)
907  {
908  return -L4_ENOSYS;
909  }
910 
911  int op_info(L4::Icu::Rights, L4::Icu::_Info &info)
912  {
913  info.features = 0;
914  info.nr_irqs = num_events_supported();
915  info.nr_msis = 0;
916 
917  return L4_EOK;
918  }
919 
920  int op_msi_info(L4::Icu::Rights, l4_umword_t, l4_uint64_t, l4_icu_msi_info_t &)
921  { return -L4_ENOSYS; }
922 
923  int op_mask(L4::Icu::Rights, l4_umword_t)
924  { return -L4_ENOSYS; }
925 
926  int op_unmask(L4::Icu::Rights, l4_umword_t)
927  { return -L4_ENOREPLY; }
928 
929  int op_set_mode(L4::Icu::Rights, l4_umword_t, l4_umword_t)
930  { return -L4_ENOSYS; }
931 
943  void reset_queue_config(unsigned idx, unsigned num_max,
944  bool inc_generation = false)
945  {
946  _device_config->reset_queue(idx, num_max, inc_generation);
947  }
948 
953  void init_mem_info(unsigned num)
954  {
955  _mem_info.init(num);
956  }
957 
967  {
968  reset();
969  _device_config->set_failed();
970  }
971 
985  bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
986  {
987  l4virtio_config_queue_t volatile const *qc;
988  qc = _device_config->qconfig(qn);
989 
990  if (!qc->ready)
991  {
992  q->disable();
993  return true;
994  }
995 
996  // read to local variables before check
997  l4_uint32_t num = qc->num;
998  l4_uint64_t desc = qc->desc_addr;
999  l4_uint64_t avail = qc->avail_addr;
1000  l4_uint64_t used = qc->used_addr;
1001 
1002  if (0)
1003  printf("%p: setup queue: num=0x%x max_num=0x%x desc=0x%llx avail=0x%llx used=0x%llx\n",
1004  this, num, num_max, desc, avail, used);
1005 
1006  if (!num || num > num_max)
1007  return false;
1008 
1009  // num must be power of two
1010  if (num & (num - 1))
1011  return false;
1012 
1013  if (desc & 0xf)
1014  return false;
1015 
1016  if (avail & 0x1)
1017  return false;
1018 
1019  if (used & 0x3)
1020  return false;
1021 
1022  auto const *desc_info = _mem_info.find(desc, Virtqueue::desc_size(num));
1023  if (L4_UNLIKELY(!desc_info))
1024  return false;
1025 
1026  auto const *avail_info = _mem_info.find(avail, Virtqueue::avail_size(num));
1027  if (L4_UNLIKELY(!avail_info))
1028  return false;
1029 
1030  auto const *used_info = _mem_info.find(used, Virtqueue::used_size(num));
1031  if (L4_UNLIKELY(!used_info || !used_info->is_writable()))
1032  return false;
1033 
1034  printf("shm=[%llx-%llx] local=[%lx-%lx] desc=[%llx-%llx] (%p-%p)\n",
1035  desc_info->drv_base(), desc_info->drv_base() + desc_info->size() - 1,
1036  (unsigned long)desc_info->local_base(),
1037  (unsigned long)desc_info->local_base() + desc_info->size() - 1,
1038  desc, desc + Virtqueue::desc_size(num),
1039  desc_info->local(Ptr<char>(desc)),
1040  desc_info->local(Ptr<char>(desc)) + Virtqueue::desc_size(num));
1041 
1042  printf("shm=[%llx-%llx] local=[%lx-%lx] avail=[%llx-%llx] (%p-%p)\n",
1043  avail_info->drv_base(), avail_info->drv_base() + avail_info->size() - 1,
1044  (unsigned long)avail_info->local_base(),
1045  (unsigned long)avail_info->local_base() + avail_info->size() - 1,
1046  avail, avail + Virtqueue::avail_size(num),
1047  avail_info->local(Ptr<char>(avail)),
1048  avail_info->local(Ptr<char>(avail)) + Virtqueue::avail_size(num));
1049 
1050  printf("shm=[%llx-%llx] local=[%lx-%lx] used=[%llx-%llx] (%p-%p)\n",
1051  used_info->drv_base(), used_info->drv_base() + used_info->size() - 1,
1052  (unsigned long)used_info->local_base(),
1053  (unsigned long)used_info->local_base() + used_info->size() - 1,
1054  used, used + Virtqueue::used_size(num),
1055  used_info->local(Ptr<char>(used)),
1056  used_info->local(Ptr<char>(used)) + Virtqueue::used_size(num));
1057 
1058  q->setup(num, desc_info->local(Ptr<void>(desc)),
1059  avail_info->local(Ptr<void>(avail)),
1060  used_info->local(Ptr<void>(used)));
1061  return true;
1062  }
1063 
1064  void check_n_init_shm(L4Re::Util::Unique_cap<L4Re::Dataspace> &&shm,
1065  l4_uint64_t base, l4_umword_t size, l4_addr_t offset)
1066  {
1067  if (_mem_info.full())
1069 
1070  auto const *i = _mem_info.add(base, size, offset, cxx::move(shm));
1071  printf("PORT[%p]: DMA guest [%llx-%llx] local [%lx-%lx] offset %lx\n",
1072  this, i->drv_base(), i->drv_base() + i->size() - 1,
1073  (unsigned long)i->local_base(),
1074  (unsigned long)i->local_base() + i->size() - 1,
1075  i->ds_offset());
1076  }
1077 
1087  {
1088  l4_uint32_t cmd = _device_config->get_cmd();
1089  if (L4_LIKELY(!(cmd & L4VIRTIO_CMD_MASK)))
1090  return false;
1091 
1092  switch (cmd & L4VIRTIO_CMD_MASK)
1093  {
1095  _set_status(cmd & ~L4VIRTIO_CMD_MASK);
1096  break;
1097 
1099  reconfig_queue(cmd & ~L4VIRTIO_CMD_MASK);
1100  break;
1101 
1102  default:
1103  // unknown command
1104  break;
1105  }
1106 
1107  _device_config->reset_cmd();
1108 
1109  return true;
1110  }
1111 
1112 private:
1113  void _check_n_init_shm(L4::Ipc::Snd_fpage shm_cap_fp,
1114  l4_uint64_t base, l4_umword_t size, l4_addr_t offset)
1115  {
1116  if (!shm_cap_fp.cap_received())
1118 
1120  L4Re::chkcap(server_iface()->template rcv_cap<L4Re::Dataspace>(0)));
1121  L4Re::chksys(server_iface()->realloc_rcv_cap(0));
1122 
1123  check_n_init_shm(cxx::move(ds), base, size, offset);
1124  }
1125 
1126  bool check_features_internal()
1127  {
1128  static_assert(sizeof(l4virtio_config_hdr_t::driver_features_map)
1129  == sizeof(l4virtio_config_hdr_t::dev_features_map),
1130  "Driver and device feature maps must be of the same size");
1131 
1132  for (auto i = 0u;
1133  i < sizeof(l4virtio_config_hdr_t::driver_features_map)
1134  / sizeof(l4virtio_config_hdr_t::driver_features_map[0]);
1135  i++)
1136  {
1137  // Driver must not accept features that were not offered by device
1138  if (_device_config->guest_features(i)
1139  & ~_device_config->host_features(i))
1140  return false;
1141  }
1142  return check_features();
1143  }
1144 
1145  int _set_status(unsigned _status)
1146  {
1147  Dev_config::Status status(_status);
1148 
1149  if (_status == 0)
1150  {
1151  printf("Resetting device\n");
1152  reset();
1153  }
1154 
1155  // do nothing if 'failed' is set
1156  if (status.failed())
1157  return 0;
1158 
1159  if (!status.driver_ok() && status.features_ok()
1160  && !check_features_internal())
1161  status.features_ok() = 0;
1162 
1163  if (status.running() && !check_queues())
1164  status.failed() = 1;
1165 
1166  _device_config->set_status(status);
1167  return 0;
1168  }
1169 
1170 };
1171 
1173 
1174 } // namespace Svr
1175 
1176 }
1177 
l4_umword_t size() const
Definition: l4virtio:501
l4_uint32_t get_cmd() const
Get the value from the cmd register.
Definition: l4virtio:189
Request writable mapping.
Definition: dataspace:71
Capability type for RPC interfaces (see L4::Cap<T>).
Definition: ipc_types:541
Set the status register.
Definition: virtio.h:119
unsigned long size
size
Definition: dataspace:86
Descriptor in the descriptor table.
Definition: virtqueue:93
Pointer used in virtio descriptors.
Definition: virtqueue:56
virtual void register_single_driver_irq()
callback for registering a single guest IRQ for all queues (old-style)
Definition: l4virtio:761
Read and interface specific &#39;W&#39; right for capability flex-pages.
Definition: __l4_fpage.h:176
l4_uint32_t status
Device status register (read-only).
Definition: virtio.h:166
Virtqueue implementation for the device.
Definition: virtio:94
Abstraction for L4-Virtio device config memory.
Definition: l4virtio:56
Invalid argument.
Definition: err.h:56
Status status() const
Get current device status (trusted).
Definition: l4virtio:181
Server-side L4-VIRTIO device stub.
Definition: l4virtio:731
void l4virtio_set_feature(l4_uint32_t *feature_map, unsigned feat)
Set the given feature bit in a feature map.
Definition: virtio.h:257
Unique_cap / Unique_del_cap.
bool handle_mem_cmd_write()
Check for a value in the cmd register and handle a write.
Definition: l4virtio:1086
Dev_config(l4_uint32_t vendor, l4_uint32_t device, unsigned cfg_size, l4_uint32_t num_queues=0)
Setup/Create a L4-Virtio config data space.
Definition: l4virtio:97
bool change_queue_config(l4_uint32_t num_queues)
Setup new queue configuration.
Definition: l4virtio:234
Interface for server-loop related functions.
Definition: ipc_epiface:47
bool cap_received() const
Check if the capability has been mapped.
Definition: ipc_types:438
l4virtio_config_queue_t volatile const * qconfig(unsigned index) const
Get queue read-only config data for queue with the given index.
Definition: l4virtio:251
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Definition: consts.h:389
Info to use for a specific MSI.
Definition: icu.h:180
void reset_hdr(bool inc_generation=false) const
Reset the config header to the initial contents.
Definition: l4virtio:266
void load_desc(Virtqueue::Desc const &desc, Request_processor const *p, Mem_region const **data) const
Default implementation returning the Driver_mem_region.
Definition: l4virtio:661
Common L4 ABI Data Types.
Driver_mem_list_t()
Make an empty, zero capacity list.
Definition: l4virtio:568
l4_uint32_t cmd
L4 specific command register polled by the driver iff supported.
Definition: virtio.h:187
Address cannot be translated.
Definition: virtio:337
Information about the dataspace.
Definition: dataspace:85
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false)
Trigger reset for the configuration space for queue idx.
Definition: l4virtio:943
Cap< T > make_cap(L4::Cap< T > cap, unsigned rights)
Make an L4::Ipc::Cap<T> for the given capability and rights.
Definition: ipc_types:624
L4::Cap< L4Re::Dataspace > ds() const
Get data-space capability for the shared config data space.
Definition: l4virtio:323
C++ interface of the initial environment that is provided to an L4 task.
Definition: env:85
Exception used by Queue to indicate descriptor errors.
Definition: virtio:332
l4_addr_t l4_trunc_page(l4_addr_t address) L4_NOTHROW
Round an address down to the next lower page boundary.
Definition: consts.h:364
Driver_mem_region_t(l4_uint64_t drv_base, l4_umword_t size, l4_addr_t offset, Ds_cap &&ds)
Make a local memory region for the given driver values.
Definition: l4virtio:425
Type of the device status register.
Definition: virtio:44
No reply.
Definition: err.h:65
l4_uint64_t used_addr
W: address of used ring.
Definition: virtio.h:223
void disable()
Completely disable the queue.
Definition: virtqueue:228
l4_uint64_t drv_base() const
Definition: l4virtio:495
Search for a suitable address range.
Definition: rm:115
Mem_region * find(l4_uint64_t base, l4_umword_t size) const
Find memory region containing the given driver address region.
Definition: l4virtio:627
void device_error()
Transition device into failed state.
Definition: l4virtio:966
Mem_list _mem_info
Memory region list.
Definition: l4virtio:737
Encapsulate the state for processing a VIRTIO request.
Definition: virtio:405
virtual L4::Cap< L4::Irq > device_notify_irq() const
callback to gather the device notification IRQ (old-style)
Definition: l4virtio:765
#define L4_SUPERPAGESHIFT
Size of a large page, log2-based.
Definition: consts.h:42
l4_uint16_t num
RW: number of descriptors configured for this queue.
Definition: virtio.h:213
Environment interface.
Read right for capability flex-pages.
Definition: __l4_fpage.h:160
Interface for memory-like objects.
Definition: dataspace:59
T1 max(T1 a, T1 b)
Get the maximum of a and b.
Definition: minmax:46
l4virtio_config_hdr_t const volatile * hdr() const
Get a read-only pointer to the config header.
Definition: l4virtio:316
L4::Detail::Unique_cap_impl< T, Smart_cap_auto< L4_FP_ALL_SPACES > > Unique_cap
Unique capability that implements automatic free and unmap of the capability selector.
Definition: unique_cap:54
Error helper.
long info(Stats *stats)
Get information on the dataspace.
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition: consts.h:307
driver_bfm_t::Val driver() const
Get the driver bits ( 1 to 1 ) of raw .
Definition: virtio:53
void * l4virtio_device_config(l4virtio_config_hdr_t const *cfg)
Get the pointer to the device configuration.
Definition: virtio.h:248
Region mapper interface.
bool contains(l4_uint64_t base, l4_umword_t size) const
Test if the given driver address range is within this region.
Definition: l4virtio:516
bool running() const
Check if the device is in running state.
Definition: virtio:66
virtual unsigned num_events_supported() const
Return the highest notification index supported.
Definition: l4virtio:800
IPC interface for virtio over L4 IPC.
Definition: l4virtio:50
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition: compiler.h:234
Ok.
Definition: err.h:43
static Env const * env()
Returns the initial environment for the current task.
Definition: env:103
unsigned long flags
flags
Definition: dataspace:87
Configure a queue.
Definition: virtio.h:120
L4-VIRTIO config header, provided in shared data space.
Definition: virtio.h:127
unsigned l4virtio_get_feature(l4_uint32_t *feature_map, unsigned feat)
Check if the given bit in a feature map is set.
Definition: virtio.h:281
l4_cap_idx_t cap() const
Return capability selector.
Definition: capability.h:52
features_ok_bfm_t::Val features_ok() const
Get the features_ok bits ( 3 to 3 ) of raw .
Definition: virtio:55
Cap< T > make_cap_rw(L4::Cap< T > cap)
Make an L4::Ipc::Cap<T> for the given capability with L4_CAP_FPAGE_RW rights.
Definition: ipc_types:634
unsigned long l4_umword_t
Unsigned machine word.
Definition: l4int.h:52
l4_uint16_t num_max
R: maximum number of descriptors supported by this queue.
Definition: virtio.h:211
driver_ok_bfm_t::Val driver_ok() const
Get the driver_ok bits ( 2 to 2 ) of raw .
Definition: virtio:54
Ptr< void > addr
Address stored in descriptor.
Definition: virtqueue:115
virtual L4::Cap< L4::Irq > device_notify_irq(unsigned idx)
Callback to gather the device notification IRQ (multi IRQ).
Definition: l4virtio:791
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Definition: error_helper:140
List of driver memory regions assigned to a single L4-VIRTIO transport instance.
Definition: l4virtio:553
void init(unsigned max)
Make a fresh list with capacity max.
Definition: l4virtio:574
L4::Cap< L4Re::Dataspace > ds() const
Definition: l4virtio:507
No memory.
Definition: err.h:50
#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
l4_uint16_t ready
RW: queue ready flag (read-write)
Definition: virtio.h:216
l4_uint64_t get() const
Definition: virtqueue:71
I/O error.
Definition: err.h:46
void set_status(Status status)
Set device status register.
Definition: l4virtio:212
virtual void register_driver_irq(unsigned idx)
Callback for registering an notification IRQ (multi IRQ).
Definition: l4virtio:777
void setup(unsigned num, void *desc, void *avail, void *used)
Enable this queue.
Definition: virtqueue:353
T * local(Ptr< T > p) const
Get the local address for driver address p.
Definition: l4virtio:540
void set_failed()
Set device status failed bit.
Definition: l4virtio:224
Mem_list const * mem_info() const
Get the memory region list used for this device.
Definition: l4virtio:815
failed_bfm_t::Val failed() const
Get the failed bits ( 7 to 7 ) of raw .
Definition: virtio:56
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Definition: error_helper:63
virtual bool check_features()
callback for checking the subset of accepted features
Definition: l4virtio:751
Type for device feature bitmap.
Definition: virtio:75
static unsigned long avail_size(unsigned num)
Calculate the size of the available ring for num entries.
Definition: virtqueue:283
Queue configuration entry.
Definition: virtio.h:208
Region of driver memory, that shall be managed locally.
Definition: l4virtio:380
void init_mem_info(unsigned num)
Initialize the memory region list to the given maximum.
Definition: l4virtio:953
void reset_cmd()
Reset the cmd register after execution of a command.
Definition: l4virtio:200
Region is read-only.
Definition: rm:90
void load_desc(Virtqueue::Desc const &desc, Request_processor const *p, ARG *data) const
Default implementation returning generic information.
Definition: l4virtio:688
bool reset_queue(unsigned index, unsigned num_max, bool inc_generation=false) const
Reset queue config for the given queue.
Definition: l4virtio:293
Dataspace interface.
Capability allocator.
Range error.
Definition: err.h:58
void load_desc(Virtqueue::Desc const &desc, Request_processor const *p, Virtqueue::Desc const **table) const
Default implementation for loading an indirect descriptor.
Definition: l4virtio:641
Device_t(Dev_config *dev_config)
Make a device for the given config.
Definition: l4virtio:808
static unsigned long desc_size(unsigned num)
Calculate the size of the descriptor table for num entries.
Definition: virtqueue:265
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition: l4int.h:42
l4_uint32_t negotiated_features(unsigned idx) const
Compute a specific set of negotiated features.
Definition: l4virtio:171
No sys.
Definition: err.h:60
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
Enable/disable the specified queue.
Definition: l4virtio:985
L4-VIRTIO Transport C++ API.
Definition: l4virtio:29
Mem_region const * add(l4_uint64_t drv_base, l4_umword_t size, l4_addr_t offset, Ds_cap &&ds)
Add a new region to the list.
Definition: l4virtio:593
l4_uint32_t len
Length of described buffer.
Definition: virtqueue:116
l4_uint32_t guest_features(unsigned idx) const
Return a specific set of guest features.
Definition: l4virtio:157
Mask to get command bits.
Definition: virtio.h:121
L4Re::Util::Unique_cap< L4Re::Dataspace > Ds_cap
type for storing a data-space capability internally
Definition: l4virtio:565
unsigned long l4_addr_t
Address type.
Definition: l4int.h:45
l4_addr_t ds_offset() const
Return the offset into the config dataspace where the device configuration starts.
Definition: l4virtio:329
l4_uint64_t desc_addr
W: address of descriptor table.
Definition: virtio.h:221
acked_bfm_t::Val acked() const
Get the acked bits ( 0 to 0 ) of raw .
Definition: virtio:52
void l4virtio_clear_feature(l4_uint32_t *feature_map, unsigned feat)
Clear the given feature bit in a feature map.
Definition: virtio.h:269
l4_uint64_t avail_addr
W: address of available ring.
Definition: virtio.h:222
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition: l4int.h:40
Driver_mem_region_t()
Make default empty memroy region.
Definition: l4virtio:412
Generic RPC wrapper for L4 flex-pages.
Definition: ipc_types:321
static unsigned long used_size(unsigned num)
Calculate the size of the used ring for num entries.
Definition: virtqueue:302
l4_addr_t ds_offset() const
Definition: l4virtio:504