L4Re - L4 Runtime Environment
object_registry
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /*
3  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
4  * Alexander Warg <warg@os.inf.tu-dresden.de>
5  * economic rights: Technische Universit├Ąt Dresden (Germany)
6  *
7  * This file is part of TUD:OS and distributed under the terms of the
8  * GNU General Public License 2.
9  * Please see the COPYING-GPL-2 file for details.
10  *
11  * As a special exception, you may use this file as part of a free software
12  * library without restriction. Specifically, if other files instantiate
13  * templates or use macros or inline functions from this file, or you compile
14  * this file and link it with other files to produce an executable, this
15  * file does not by itself cause the resulting executable to be covered by
16  * the GNU General Public License. This exception does not however
17  * invalidate any other reasons why the executable file might be covered by
18  * the GNU General Public License.
19  */
20 
21 #pragma once
22 
23 #include <l4/re/util/cap_alloc>
24 #include <l4/re/util/unique_cap>
25 #include <l4/re/consts>
26 #include <l4/re/env>
27 
28 #include <l4/sys/cxx/ipc_server_loop>
29 #include <l4/sys/factory>
30 #include <l4/sys/task>
31 #include <l4/sys/thread>
32 #include <l4/sys/ipc_gate>
33 
34 #include <l4/cxx/exceptions>
35 
36 namespace L4Re { namespace Util {
37 
38 /**
39  * A registry that manages server objects and their attached IPC gates for
40  * a single server loop for a specific thread.
41  *
42  * This class manages most of the setup of a server object. If necessary,
43  * an IPC gate is created, the specified thread is bound to the IPC gate.
44  * Incoming IPC is dispatched to the server object based on
45  * the label of the IPC gate.
46  *
47  * The object registry is also able to manage IRQ endpoints. They require a
48  * different method for the object creation. Otherwise they are handled in
49  * the same way as IPC gates: a server object is responsible to process
50  * the incoming interrupts.
51  */
52 class Object_registry :
53  public L4::Basic_registry,
54  public L4::Registry_iface
55 {
56  /**
57  * Handler class for stale requests from servers that have been
58  * deregistered.
59  */
60  struct Null_handler : L4::Epiface_t<Null_handler, L4::Kobject>
61  {};
62 
63 protected:
64  L4::Cap<L4::Thread> _server;
65  L4::Cap<L4::Factory> _factory;
66  L4::Ipc_svr::Server_iface *_sif;
67 
68 private:
69  Null_handler _null_handler;
70 
71 public:
72  /**
73  * Create a registry for the main thread of the task using the default factory.
74  *
75  * \param sif Server loop interface.
76  */
77  explicit
78  Object_registry(L4::Ipc_svr::Server_iface *sif)
79  : _server(L4Re::Env::env()->main_thread()),
80  _factory(L4Re::Env::env()->factory()),
81  _sif(sif)
82  {}
83 
84  /**
85  * Create a registry for arbitrary threads.
86  *
87  * \param sif Server loop interface.
88  * \param server Capability to the thread that executes the server objects.
89  * \param factory Capability to a factory object capable of creating new
90  * IPC gates.
91  */
92  Object_registry(L4::Ipc_svr::Server_iface *sif,
93  L4::Cap<L4::Thread> server,
94  L4::Cap<L4::Factory> factory)
95  : _server(server), _factory(factory), _sif(sif)
96  {}
97 
98 private:
99  typedef L4::Ipc_svr::Server_iface Server_iface;
100  typedef Server_iface::Demand Demand;
101 
102  L4::Cap<L4::Rcv_endpoint>
103  _register_ep(L4::Epiface *o, L4::Cap<L4::Rcv_endpoint> ep,
104  Demand const &demand)
105  {
106  int err = _sif->alloc_buffer_demand(demand);
107  if (err < 0)
108  return L4::Cap<L4::Rcv_endpoint>(err | L4_INVALID_CAP_BIT);
109 
110  l4_umword_t id = l4_umword_t(o);
111  err = l4_error(ep->bind_thread(_server, id));
112  if (err < 0)
113  return L4::Cap<L4::Rcv_endpoint>(err | L4_INVALID_CAP_BIT);
114 
115  err = o->set_server(_sif, ep);
116  if (err < 0)
117  return L4::Cap<L4::Rcv_endpoint>(err | L4_INVALID_CAP_BIT);
118 
119  return ep;
120  }
121 
122  L4::Cap<void> _register_ep(L4::Epiface *o, char const *service,
123  Demand const &demand)
124  {
125  L4::Cap<L4::Rcv_endpoint> cap = L4Re::Env::env()->get_cap<L4::Rcv_endpoint>(service);
126  if (!cap.is_valid())
127  return cap;
128 
129  return _register_ep(o, cap, demand);
130  }
131 
132  L4::Cap<void> _register_gate(L4::Epiface *o, Demand const &demand)
133  {
134  int err = _sif->alloc_buffer_demand(demand);
135  if (err < 0)
136  return L4::Cap<void>(err | L4_INVALID_CAP_BIT);
137 
138  auto cap = L4Re::Util::make_unique_cap<L4::Kobject>();
139 
140  if (!cap.is_valid())
141  return cap.get();
142 
143  l4_umword_t id = l4_umword_t(o);
144  err = l4_error(_factory->create_gate(cap.get(), _server, id));
145  if (err < 0)
146  return L4::Cap<void>(err | L4_INVALID_CAP_BIT);
147 
148  err = o->set_server(_sif, cap.get(), true);
149  if (err < 0)
150  return L4::Cap<void>(err | L4_INVALID_CAP_BIT);
151 
152  return cap.release();
153  }
154 
155  L4::Cap<L4::Irq> _register_irq(L4::Epiface *o,
156  Demand const &demand)
157  {
158  int err = _sif->alloc_buffer_demand(demand);
159  if (err < 0)
160  return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT);
161 
162  auto cap = L4Re::Util::make_unique_cap<L4::Irq>();
163 
164  if (!cap.is_valid())
165  return cap.get();
166 
167  l4_umword_t id = l4_umword_t(o);
168  err = l4_error(_factory->create(cap.get()));
169  if (err < 0)
170  return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT);
171 
172  err = l4_error(cap->bind_thread(_server, id));
173  if (err < 0)
174  return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT);
175 
176  err = o->set_server(_sif, cap.get(), true);
177  if (err < 0)
178  return L4::Cap<L4::Irq>(err | L4_INVALID_CAP_BIT);
179 
180  return cap.release();
181  }
182 
183  static Demand _get_buffer_demand(L4::Epiface *o)
184  { return o->get_buffer_demand(); }
185 
186  template<typename T>
187  static Demand _get_buffer_demand(T *,
188  typename L4::Kobject_typeid<typename T::Interface>::Demand
189  d = typename L4::Kobject_typeid<typename T::Interface>::Demand())
190  { return d; }
191 
192 public:
193  /**
194  * Register a new server object to a pre-allocated receive endpoint.
195  *
196  * \param o Server object that handles IPC requests.
197  * \param service Name of a pre-allocated receive endpoint.
198  *
199  * \return The capability the server object was registered with.
200  */
201  L4::Cap<void> register_obj(L4::Epiface *o, char const *service) override
202  {
203  return _register_ep(o, service, _get_buffer_demand(o));
204  }
205 
206  /**
207  * Register a new server object on a newly allocated capability.
208  *
209  * \param o Server object that handles IPC requests.
210  *
211  * \return The capability the server object was registered with.
212  *
213  * The IPC gate will be allocated using the registry's factory.
214  */
215  L4::Cap<void> register_obj(L4::Epiface *o) override
216  {
217  return _register_gate(o, _get_buffer_demand(o));
218  }
219 
220  /**
221  * Register a handler for an interrupt.
222  *
223  * \param o Server object that handles IRQs.
224  *
225  * \return The capability the server object was registered with.
226  *
227  * The IRQ will be newly allocated using the registry's factory object.
228  */
229  L4::Cap<L4::Irq> register_irq_obj(L4::Epiface *o) override
230  {
231  return _register_irq(o, _get_buffer_demand(o));
232  }
233 
234  // pass access to deprecated register_irq_obj
235  using L4::Registry_iface::register_irq_obj;
236 
237  /**
238  * Register a handler for an already existing interrupt.
239  *
240  * \param o Server object that handles the IPC.
241  * \param irq Capability to a receive endpoint, may be a hardware or
242  * software interrupt or an IPC gate.
243  *
244  * \return The capability the server object was registered with.
245  *
246  */
247 
248  L4::Cap<L4::Rcv_endpoint>
249  register_obj(L4::Epiface *o, L4::Cap<L4::Rcv_endpoint> ep) override
250  {
251  return _register_ep(o, ep, _get_buffer_demand(o));
252  }
253 
254 
255  /**
256  * Remove a server object from the handler list.
257  *
258  * \param o Server object to unbind.
259  * \param unmap Specifies if the object capability shall be unmapped (true)
260  * or not. The default (true) is to unmap the capability.
261  *
262  * The capability used by the server object will be unmapped if `unmap` is
263  * true.
264  */
265  void unregister_obj(L4::Epiface *o, bool unmap = true) override
266  {
267  L4::Epiface::Stored_cap c;
268 
269  if (!o || !o->obj_cap().is_valid())
270  return;
271 
272  c = o->obj_cap();
273 
274  // make sure unhandled ipc ends up with the null handler
275  L4::Thread::Modify_senders todo;
276  todo.add(~3UL, reinterpret_cast<l4_umword_t>(o),
277  ~0UL, reinterpret_cast<l4_umword_t>((L4::Epiface*)&_null_handler));
278  _server->modify_senders(todo);
279 
280  if (unmap)
281  L4::Cap<L4::Task>(L4Re::This_task)->unmap(c.fpage(), L4_FP_ALL_SPACES);
282 
283  // we use bit 4 to indicated an internally allocated cap
284  if (c.managed())
285  cap_alloc.free(c);
286 
287  o->set_server(0, L4::Cap<void>::Invalid);
288  }
289 };
290 
291 /**
292  * A server loop object which has a Object_registry included.
293  */
294 template< typename LOOP_HOOKS = L4::Ipc_svr::Default_loop_hooks >
295 class Registry_server : public L4::Server<LOOP_HOOKS>
296 {
297 private:
298  typedef L4::Server<LOOP_HOOKS> Base;
299  Object_registry _registry;
300 
301 public:
302  /**
303  * Create a new server loop object for the main thread of the task.
304  *
305  * \pre Must be called from the main thread or behaviour is undefined.
306  */
307  Registry_server() : Base(l4_utcb()), _registry(this)
308  {}
309 
310  /**
311  * Create a new server loop object for an arbitrary thread and factory.
312  *
313  * \param utcb The UTCB of the thread running the server loop.
314  * \param server Capability to thread running the server loop.
315  * \param factory Capability to factory object used to create new IPC gates.
316  */
317  Registry_server(l4_utcb_t *utcb, L4::Cap<L4::Thread> server,
318  L4::Cap<L4::Factory> factory)
319  : Base(utcb), _registry(this, server, factory)
320  {}
321 
322  /** Return registry of this server loop. */
323  Object_registry const *registry() const { return &_registry; }
324  /** Return registry of this server loop. */
325  Object_registry *registry() { return &_registry; }
326 
327  /**
328  * Start the server loop.
329  */
330  void L4_NORETURN loop()
331  { Base::template loop<L4::Runtime_error, Object_registry &>(_registry); }
332 };
333 
334 }}