L4Re - L4 Runtime Environment
l4virtio
1 // vi:ft=cpp
2 /*
3  * (c) 2013-2014 Alexander Warg <warg@os.inf.tu-dresden.de>
4  * Matthias Lange <matthias.lange@kernkonzept.com>
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  *
10  * As a special exception, you may use this file as part of a free software
11  * library without restriction. Specifically, if other files instantiate
12  * templates or use macros or inline functions from this file, or you compile
13  * this file and link it with other files to produce an executable, this
14  * file does not by itself cause the resulting executable to be covered by
15  * the GNU General Public License. This exception does not however
16  * invalidate any other reasons why the executable file might be covered by
17  * the GNU General Public License.
18  */
19 
20 #pragma once
21 
22 #include "virtio.h"
23 #include <l4/sys/capability>
24 #include <l4/sys/cxx/ipc_client>
25 #include <l4/re/dataspace>
26 #include <l4/sys/irq>
27 #include <l4/cxx/utils>
28 
29 namespace L4virtio {
30 class Device :
31  public L4::Kobject_t<Device, L4::Kobject, L4VIRTIO_PROTOCOL,
32  L4::Type_info::Demand_t<1> >
33 {
34 public:
35  typedef l4virtio_config_queue_t Config_queue;
36  struct Config_hdr : l4virtio_config_hdr_t
37  {
38  Config_queue *queues() const
39  { return l4virtio_config_queues(this); }
40 
41  template <typename T>
42  T *device_config() const
43  {
44  return static_cast<T*>(l4virtio_device_config(this));
45  }
46 
47  int config_queue(unsigned num, L4::Cap<L4::Triggerable> out_notify,
48  L4::Cap<L4::Triggerable> in_notify,
49  l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
50  {
51  return send_cmd(L4VIRTIO_CMD_CFG_QUEUE | num,
52  out_notify, in_notify, to);
53  }
54 
55  int set_status(unsigned new_status, L4::Cap<L4::Triggerable> out_notify,
56  L4::Cap<L4::Triggerable> in_notify,
57  l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
58  {
59  return send_cmd(L4VIRTIO_CMD_SET_STATUS | new_status,
60  out_notify, in_notify, to);
61  }
62 
63  int send_cmd(unsigned command, L4::Cap<L4::Triggerable> out_notify,
64  L4::Cap<L4::Triggerable> in_notify,
65  l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
66  {
67  cxx::write_now(&cmd, command);
68 
69  if (out_notify)
70  out_notify->trigger();
71 
72  auto utcb = l4_utcb();
73  auto ipc_to = l4_timeout(L4_IPC_TIMEOUT_0, to);
74 
75  do
76  {
77  if (in_notify)
78  if (l4_ipc_error(l4_ipc_receive(in_notify.cap(), utcb, ipc_to),
79  utcb) == L4_IPC_RETIMEOUT)
80  break;
81  }
82  while (cxx::access_once(&cmd));
83 
84  return cxx::access_once(&cmd) ? -L4_EBUSY : L4_EOK;
85  }
86  };
87 
88  L4_INLINE_RPC(long, set_status, (unsigned status));
89  L4_INLINE_RPC(long, config_queue, (unsigned queue));
90  L4_INLINE_RPC(long, register_ds, (L4::Ipc::Cap<L4Re::Dataspace> ds_cap,
91  l4_uint64_t base, l4_umword_t offset,
92  l4_umword_t size));
93 
94  L4_INLINE_RPC(long, register_iface, (L4::Ipc::Cap<L4::Triggerable> guest_irq,
95  L4::Ipc::Out<L4::Cap<L4::Triggerable> > host_irq,
96  L4::Ipc::Out<L4::Cap<L4Re::Dataspace> > config_ds));
97 
98  typedef L4::Typeid::Rpcs<set_status_t, config_queue_t, register_iface_t, register_ds_t> Rpcs;
99 };
100 
101 }