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
36namespace 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 */
52class 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
63protected:
64  L4::Cap<L4::Thread> _server;
65  L4::Cap<L4::Factory> _factory;
66  L4::Ipc_svr::Server_iface *_sif;
67
68private:
69  Null_handler _null_handler;
70
71public:
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
98private:
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
192public:
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   * \retval L4::Cap<void> The capability known as `service` on success.
200   * \retval L4::Cap<void>::Invalid No capability with the given name found.
201   *
202   * The interface must be freed with unregister_obj() by the caller
203   * to unbind the thread from the capability.
204   */
205  L4::Cap<void> register_obj(L4::Epiface *o, char const *service) override
206  {
207    return _register_ep(o, service, _get_buffer_demand(o));
208  }
209
210  /**
211   * Register a new server object on a newly allocated capability.
212   *
213   * \param o  Server object that handles IPC requests.
214   *
215   * \retval L4::Cap<void> A valid capability to a new IPC gate.
216   * \retval L4::Cap<void>::Invalid  The allocation of the IPC gate
217   *                                 has failed.
218   *
219   * The IPC gate will be allocated using the registry's factory. The
220   * caller must call unregister_obj() to free all resources.
221   */
222  L4::Cap<void> register_obj(L4::Epiface *o) override
223  {
224    return _register_gate(o, _get_buffer_demand(o));
225  }
226
227  /**
228   * Register a handler for an interrupt.
229   *
230   * \param o  Server object that handles IRQs.
231   *
232   * \retval L4::Cap<L4::Irq>           Capability to a new IRQ object on success.
233   * \retval L4::Cap<L4::Irq>::Invalid  The allocation of the IRQ has failed.
234   *
235   * The IRQ will be newly allocated using the registry's factory object. The
236   * caller must call unregister_obj() to free all resources.
237   */
238  L4::Cap<L4::Irq> register_irq_obj(L4::Epiface *o) override
239  {
240    return _register_irq(o, _get_buffer_demand(o));
241  }
242
243  // pass access to deprecated register_irq_obj
244  using L4::Registry_iface::register_irq_obj;
245
246  /**
247   * Register a handler for an already existing interrupt.
248   *
249   * \param o    Server object that handles the IPC.
250   * \param ep   Capability to a receive endpoint, may be a hardware or
251   *             software interrupt or an IPC gate.
252   *
253   * \retval L4::Cap<L4::Rcv_endpoint>           Capability `ep` on success.
254   * \retval L4::Cap<L4::Rcv_endpoint>::Invalid  The IRQ attach operation has failed.
255   *
256   * The interface must be freed with unregister_obj() by the caller
257   * to unbind the thread from the capability.
258   */
259  L4::Cap<L4::Rcv_endpoint>
260  register_obj(L4::Epiface *o, L4::Cap<L4::Rcv_endpoint> ep) override
261  {
262    return _register_ep(o, ep, _get_buffer_demand(o));
263  }
264
265
266  /**
267   * Remove a server object from the handler list.
268   *
269   * \param o      Server object to unbind.
270   * \param unmap  Specifies if the object capability shall be unmapped (true)
271   *               or not. The default (true) is to unmap the capability.
272   *
273   * The capability used by the server object will be unmapped if `unmap` is
274   * true.
275   */
276  void unregister_obj(L4::Epiface *o, bool unmap = true) override
277  {
278    L4::Epiface::Stored_cap c;
279
280    if (!o || !o->obj_cap().is_valid())
281      return;
282
283    c = o->obj_cap();
284
285    // make sure unhandled ipc ends up with the null handler
286    L4::Thread::Modify_senders todo;
287    todo.add(~3UL, reinterpret_cast<l4_umword_t>(o),
288             ~0UL, reinterpret_cast<l4_umword_t>((L4::Epiface*)&_null_handler));
289    _server->modify_senders(todo);
290
291    if (unmap)
292      L4::Cap<L4::Task>(L4Re::This_task)->unmap(c.fpage(), L4_FP_ALL_SPACES);
293
294    // we use bit 4 to indicated an internally allocated cap
295    if (c.managed())
296      cap_alloc.free(c);
297
298    o->set_server(0, L4::Cap<void>::Invalid);
299  }
300};
301
302/**
303 * A server loop object which has a Object_registry included.
304 */
305template< typename LOOP_HOOKS = L4::Ipc_svr::Default_loop_hooks >
306class Registry_server : public L4::Server<LOOP_HOOKS>
307{
308private:
309  typedef L4::Server<LOOP_HOOKS> Base;
310  Object_registry _registry;
311
312public:
313  /**
314   * Create a new server loop object for the main thread of the task.
315   *
316   * \pre Must be called from the main thread or behaviour is undefined.
317   */
318  Registry_server() : _registry(this)
319  {}
320
321  /**
322   * Create a new server loop object for an arbitrary thread and factory.
323   *
324   * \param utcb    The UTCB of the thread running the server loop.
325   * \param server  Capability to thread running the server loop.
326   * \param factory Capability to factory object used to create new IPC gates.
327   *
328   * \deprecated{Note that this variant of the constructor is deprecated,
329   * please do not supply the UTCB pointer, it's not used.}
330   */
331  Registry_server(l4_utcb_t *, L4::Cap<L4::Thread> server,
332                  L4::Cap<L4::Factory> factory)
333  : _registry(this, server, factory)
334  {}
335
336  /**
337   * Create a new server loop object for an arbitrary thread and factory.
338   *
339   * \param server  Capability to thread running the server loop.
340   * \param factory Capability to factory object used to create new IPC gates.
341   */
342  Registry_server(L4::Cap<L4::Thread> server,
343                  L4::Cap<L4::Factory> factory)
344  : _registry(this, server, factory)
345  {}
346
347  /** Return registry of this server loop. */
348  Object_registry const *registry() const { return &_registry; }
349  /** Return registry of this server loop. */
350  Object_registry *registry() { return &_registry; }
351
352  /**
353   * Start the server loop.
354   *
355   * \param utcb The UTCB of the thread running the server loop, defaults to
356   *             l4_utcb().
357   */
358  void L4_NORETURN loop(l4_utcb_t *utcb = l4_utcb())
359  { Base::template loop<L4::Runtime_error, Object_registry &>(_registry, utcb); }
360};
361
362}}
363