L4Re - L4 Runtime Environment
ipc_epiface
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /*
3  * (c) 2014-2015 Alexander Warg <alexander.warg@kernkonzept.com>
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 #pragma GCC system_header
20 
21 #include "capability.h"
22 #include "ipc_server"
23 #include "ipc_string"
24 #include <l4/sys/types.h>
25 #include <l4/sys/utcb.h>
26 #include <l4/sys/__typeinfo.h>
27 #include <l4/sys/meta>
28 #include <l4/cxx/type_traits>
29 
30 namespace L4 {
31 
32 // forward for Irqep_t
33 class Irq;
34 class Rcv_endpoint;
35 
36 namespace Ipc_svr {
37 
38 class Timeout;
39 
40 /**
41  * \ingroup cxx_ipc_server
42  * \brief Interface for server-loop related functions.
43  *
44  * This interface provides access to high-level server-loop related functions,
45  * such as management of receive buffers and timeouts.
46  */
47 class Server_iface
48 {
49 private:
50  Server_iface(Server_iface const &);
51  Server_iface const &operator = (Server_iface const &);
52 
53 public:
54  /// Data type expressing server-side demand for receive buffers.
55  typedef L4::Type_info::Demand Demand;
56 
57  /// Make a server interface
58  Server_iface() {}
59 
60  // Destroy the server interface
61  virtual ~Server_iface() = 0;
62 
63  /**
64  * \brief Tells the server to allocate buffers for the given demand.
65  * \param demand The total server-side demand of receive buffers needed for
66  * a given interface, see Demand.
67  *
68  * This function is not called by user applications directly. Usually the
69  * server implementation or the registry implementation calls this function
70  * whenever a new object is registered at the server.
71  */
72  virtual int alloc_buffer_demand(Demand const &demand) = 0;
73 
74  /**
75  * \brief Get capability slot allocated to the given receive buffer.
76  * \param index The receive buffer index of the expected capability
77  * argument (0 <= \c index < \c caps registered with
78  * alloc_buffer_demand()).
79  * \pre 0 <= \c index < \c caps registered with alloc_buffer_demand()
80  * \return Capability slot currently allocated to the given receive buffer.
81  */
82  virtual L4::Cap<void> get_rcv_cap(int index) const = 0;
83 
84  /**
85  * \brief Allocate a new capability for the given receive buffer.
86  * \param index The receive buffer index of the expected capability
87  * argument (0 <= \c index < \c caps registered with
88  * alloc_buffer_demand()).
89  * \pre 0 <= \c index < \c caps registered with alloc_buffer_demand()
90  * \return 0 on success, < 0 on error.
91  */
92  virtual int realloc_rcv_cap(int index) = 0;
93 
94  /**
95  * \brief Add a timeout to the server internal timeout queue.
96  * \param timeout The timeout object to register.
97  * \param time The time (absolute) at which the timeout shall expire.
98  * \pre timeout must not be in any queue.
99  * \return 0 on success, 1 if timeout is already expired, < 0 on error.
100  */
101  virtual int add_timeout(Timeout *timeout, l4_kernel_clock_t time) = 0;
102 
103  /**
104  * \brief Remove the given timeout from the timer queue.
105  * \param timeout The timout object to remove.
106  * \return 0 on success, < 0 on error.
107  */
108  virtual int remove_timeout(Timeout *timeout) = 0;
109 
110  /**
111  * \brief Get given receive buffer as typed capability.
112  * \see get_rcv_cap()
113  * \param index The receive buffer index of the expected capability
114  * argument. (0 <= \c index < \c caps registered with
115  * alloc_buffer_demand().)
116  * \pre 0 <= \c index < \c caps registered with alloc_buffer_demand()
117  * \return Capability slot currently allocated to the given receive buffer.
118  * \note This is a convenience wrapper for get_rcv_cap() to avoid
119  * L4::cap_cast<>().
120  */
121  template<typename T>
122  L4::Cap<T> rcv_cap(int index) const
123  { return L4::cap_cast<T>(get_rcv_cap(index)); }
124 
125  /**
126  * \brief Get receive cap with the given index as generic (void) type.
127  * \param index The index of the cap receive buffer of the expected
128  * capability. (0 <= \c index < \c caps registered with
129  * alloc_buffer_demand().)
130  * \return Capability slot currently allocated to the given capability
131  * buffer.
132  * \note This is a convenience wrapper for get_rcv_cap().
133  */
134  L4::Cap<void> rcv_cap(int index) const
135  { return get_rcv_cap(index); }
136 };
137 
138 inline Server_iface::~Server_iface() {}
139 
140 } // namespace Ipc_svr
141 
142 struct Epiface
143 {
144  Epiface(Epiface const &) = delete;
145  Epiface &operator = (Epiface const &) = delete;
146 
147  /// Type for abstract server interface.
148  typedef Ipc_svr::Server_iface Server_iface;
149  /// Type for server-side receive buffer demand.
150  typedef Ipc_svr::Server_iface::Demand Demand;
151 
152  class Stored_cap : public Cap<void>
153  {
154  private:
155  enum { Managed = 0x10 };
156 
157  public:
158  Stored_cap() = default;
159  Stored_cap(Cap<void> const &c, bool managed = false)
160  : Cap<void>((c.cap() & L4_CAP_MASK) | (managed ? Managed : 0))
161  {
162  static_assert (!(L4_CAP_MASK & Managed), "conflicting bits used...");
163  }
164 
165  bool managed() const { return cap() & Managed; }
166  };
167 
168  /// Make a server object
169  Epiface() : _data(0) {}
170 
171  /**
172  * The abstract handler for client requests to the object.
173  * \param tag The message tag for this invocation.
174  * \param rights The rights bits in the invoked capability.
175  * \param utcb The UTCB used for the invocation.
176  * \retval -L4_ENOREPLY No reply message is send.
177  * \retval <0 Error, reply with error code.
178  * \retval >=0 Success, reply with return value.
179  *
180  * This function must be implemented by application specific server
181  * objects.
182  */
183  virtual l4_msgtag_t dispatch(l4_msgtag_t tag, unsigned rights,
184  l4_utcb_t *utcb) = 0;
185 
186  /**
187  * Get the server-side receive buffer demand for this object.
188  * \note This function is usually not implemented directly, but by using
189  * Server_object_t template with an IPC interface definition.
190  * \return The needed server-side receive buffers for this object
191  */
192  virtual Demand get_buffer_demand() const = 0; //{ return Demand(0); }
193 
194  /// Destroy the object
195  virtual ~Epiface() = 0;
196 
197  /**
198  * Get the capability to the kernel object belonging to this object.
199  * \return Capability for the kernel object behind the server.
200  *
201  * This is usually either an Ipc_gate or an Irq.
202  */
203  Stored_cap obj_cap() const { return _cap; }
204 
205  /**
206  * Get pointer to server interface at which the object is currently registered.
207  * \return Pointer to the server at which the object is currently registered,
208  * NULL if the object is not registered at any server.
209  */
210  Server_iface *server_iface() const { return _data; }
211 
212  /**
213  * Set server registration info for the object.
214  * \param srv The server to register at
215  * \param cap The capability that connects the object.
216  * \param managed Mark the capability as managed or unmanaged. Typical
217  * server implementations use this flag to remember whether
218  * the capability was internally allocated or not.
219  * \return 0 on success, -L4_EINVAL if the srv and cap are not consistent.
220  */
221  int set_server(Server_iface *srv, Cap<void> cap, bool managed = false)
222  {
223  if ((srv && cap) || (!srv && !cap))
224  {
225  _data = srv;
226  _cap = Stored_cap(cap, managed);
227  return 0;
228  }
229 
230  return -L4_EINVAL;
231  }
232 
233  /**
234  * Deprecated server registration function.
235  */
236  void set_obj_cap(Cap<void> const &cap) { _cap = cap; }
237 
238 private:
239  Server_iface *_data;
240  Stored_cap _cap;
241 };
242 
243 inline Epiface::~Epiface() {}
244 
245 template<typename RPC_IFACE, typename BASE = Epiface>
246 struct Epiface_t0 : BASE
247 {
248  /// Data type of the IPC interface definition
249  typedef RPC_IFACE Interface;
250 
251  /// Get the server-side buffer demand based in \a IFACE.
252  typename Type_info::Demand get_buffer_demand() const
253  { return typename Kobject_typeid<RPC_IFACE>::Demand(); }
254 
255  /**
256  * Get the (typed) capability to this object.
257  * \return Capability for the kernel object behind the server.
258  */
259  Cap<RPC_IFACE> obj_cap() const
260  { return L4::cap_cast<RPC_IFACE>(BASE::obj_cap()); }
261 };
262 
263 template<typename Derived, typename BASE = Epiface,
264  bool = cxx::is_polymorphic<BASE>::value>
265 struct Irqep_t : Epiface_t0<void, BASE>
266 {
267  l4_msgtag_t dispatch(l4_msgtag_t, unsigned, l4_utcb_t *) final
268  {
269  static_cast<Derived*>(this)->handle_irq();
270  return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
271  }
272 
273  /**
274  * Get the (typed) capability to this object.
275  * \return Capability for the kernel object behind the server.
276  */
277  Cap<L4::Irq> obj_cap() const
278  { return L4::cap_cast<L4::Irq>(BASE::obj_cap()); }
279 };
280 
281 template<typename Derived, typename BASE>
282 struct Irqep_t<Derived, BASE, false> : Epiface_t0<void, BASE>
283 {
284  l4_msgtag_t dispatch(l4_msgtag_t, unsigned, l4_utcb_t *)
285  {
286  static_cast<Derived*>(this)->handle_irq();
287  return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
288  }
289 
290  /**
291  * Get the (typed) capability to this object.
292  * \return Capability for the kernel object behind the server.
293  */
294  Cap<L4::Irq> obj_cap() const
295  { return L4::cap_cast<L4::Irq>(BASE::obj_cap()); }
296 };
297 
298 /**
299  * Abstract interface for object registries.
300  *
301  * An object registry allows to register L4::Epiface objects at a server
302  * loop either for synchronous RPC messages or for asynchronous IRQ
303  * messages.
304  */
305 class Registry_iface
306 {
307 public:
308  virtual ~Registry_iface() = 0;
309 
310  /**
311  * Register an L4::Epiface for an IPC gate available in the applications
312  * environment under the name `service`.
313  * \param o Pointer to an Epiface object that shall be registered.
314  * \param service Name of the capability that shall be used to connect
315  * `o` to as a server-side object.
316  * \retval L4::Cap<void> The capability known as `service` on success.
317  * \retval L4::Cap<void>::Invalid No capability with the given name found.
318  *
319  * After a successful call to this function `o->obj_cap()` is equal
320  * to the capability in the environment with the name given by `service`.
321  */
322  virtual L4::Cap<void>
323  register_obj(L4::Epiface *o, char const *service) = 0;
324 
325  /**
326  * Register `o` as server-side object for synchronous RPC.
327  * \param o Pointer to an Epiface object that shall be registered as
328  * server-side object for RPC.
329  * \retval L4::Cap<void> A valid capability to a new IPC gate.
330  * \retval L4::Cap<void>::Invalid The allocation of the IPC gate
331  * has failed.
332  *
333  * After successful registration `o->obj_cap()` will be the capability
334  * of the allocated IPC gate.
335  *
336  * The function may allocate a capability slot for the object. In that
337  * case unregister_obj() is responsible for freeing the slot as well.
338  */
339  virtual L4::Cap<void>
340  register_obj(L4::Epiface *o) = 0;
341 
342  /**
343  * Register `o` as server-side object for asynchronous IRQs.
344  * \param o Pointer to an Epiface object that shall be registered as
345  * server-side object for IRQs.
346  * \retval L4::Cap<L4::Irq> Capability to a new IRQ object on success.
347  * \retval L4::Cap<L4::Irq>::Invalid The allocation of the IRQ has failed.
348  *
349  * After successful registration `o->obj_cap()` will be the capability
350  * of the allocated IRQ object.
351  *
352  * The function may allocate a capability slot for the object. In that
353  * case unregister_obj() is responsible for freeing the slot as well.
354  */
355  virtual L4::Cap<L4::Irq> register_irq_obj(L4::Epiface *o) = 0;
356 
357  /**
358  * Register `o` as server-side object for asynchronous IRQs.
359  * \param o Pointer to an Epiface object that shall be registered as
360  * server-side object for IRQs.
361  * \param ep Capability to an already allocated IRQ object where `o`
362  * shall be attached as server-side handler.
363  * \retval L4::Cap<L4::Irq> Capability to the given IRQ object on success.
364  * \retval L4::Cap<L4::Irq>::Invalid The IRQ attach operation has failed.
365  *
366  * After successful registration `o->obj_cap()` will be equal to `irq`.
367  */
368  virtual L4::Cap<L4::Rcv_endpoint>
369  register_obj(L4::Epiface *o, L4::Cap<L4::Rcv_endpoint> ep) = 0;
370 
371  L4::Cap<L4::Irq>
372  register_irq_obj(L4::Epiface *o, L4::Cap<L4::Irq> irq)
373  L4_DEPRECATED("Use register_obj() instead")
374  { return cap_reinterpret_cast<L4::Irq>(register_obj(o, cap_reinterpret_cast<L4::Rcv_endpoint>(irq))); }
375 
376  /**
377  * Unregister the given object `o` from the server.
378  * \param o Pointer to the Epiface object that shall be unregistered.
379  * The object must have been registered with any of the
380  * register methods if Registry_iface.
381  * \param unmap If true the capability `o->obj_cap()` shall be unmapped
382  * from the local object space.
383  *
384  * The function always unmaps and frees the capability if it was
385  * allocated by either Registry_iface::register_irq_obj(L4::Epiface *),
386  * or by Registry_iface::register_obj(L4::Epiface *).
387  */
388  virtual void
389  unregister_obj(L4::Epiface *o, bool unmap = true) = 0;
390 };
391 
392 inline Registry_iface::~Registry_iface() {}
393 
394 namespace Ipc {
395 namespace Detail {
396 
397 using namespace L4::Typeid;
398 
399 template<typename IFACE>
400 struct Meta_svr
401 {
402  long op_num_interfaces(L4::Meta::Rights)
403  { return 1; }
404 
405  long op_interface(L4::Meta::Rights, l4_umword_t ifx, long &proto, L4::Ipc::String<char> &name)
406  {
407  if (ifx > 0)
408  return -L4_ERANGE;
409  proto = L4::kobject_typeid<IFACE>()->proto();
410  name.copy_in(L4::kobject_typeid<IFACE>()->name());
411  return 0;
412  }
413 
414  long op_supports(L4::Meta::Rights, l4_mword_t proto)
415  { return L4::kobject_typeid<IFACE>()->has_proto(proto); }
416 };
417 
418 template<typename IFACE, typename LIST>
419 struct _Dispatch;
420 
421 // No match dispatcher found
422 template<typename IFACE>
423 struct _Dispatch<IFACE, Iface_list_end>
424 {
425  template< typename THIS, typename A1, typename A2 >
426  static l4_msgtag_t f(THIS *, l4_msgtag_t, A1, A2 &)
427  { return l4_msgtag(-L4_EBADPROTO, 0, 0, 0); }
428 };
429 
430 // call matching p_dispatch() function
431 template<typename IFACE, typename I, typename LIST >
432 struct _Dispatch<IFACE, Iface_list<I, LIST> >
433 {
434  // special handling for the meta protocol, to avoid 'using' murx
435  template< typename THIS >
436  static l4_msgtag_t _f(THIS *, l4_msgtag_t tag, unsigned r,
437  l4_utcb_t *utcb, True::type)
438  {
439  using L4::Ipc::Msg::dispatch_call;
440  typedef L4::Meta::Rpcs Meta;
441  typedef Meta_svr<IFACE> Msvr;
442  return dispatch_call<Meta>((Msvr *)0, utcb, tag, r);
443  }
444 
445  // normal dispatch to the op_<func> methods of \a self.
446  template< typename THIS >
447  static l4_msgtag_t _f(THIS *self, l4_msgtag_t t, unsigned r,
448  l4_utcb_t *utcb, False::type)
449  {
450  using L4::Ipc::Msg::dispatch_call;
451  return dispatch_call<typename I::iface_type::Rpcs>(self, utcb, t, r);
452  }
453 
454  // dispatch function with switch for meta protocol
455  template< typename THIS >
456  static l4_msgtag_t f(THIS *self, l4_msgtag_t tag, unsigned r,
457  l4_utcb_t *utcb)
458  {
459  if (I::Proto == tag.label())
460  return _f(self, tag, r, utcb, Bool<I::Proto == (long)L4_PROTO_META>());
461 
462  return _Dispatch<IFACE, typename LIST::type>::f(self, tag, r, utcb);
463  }
464 };
465 
466 template<typename IFACE>
467 struct Dispatch :
468  _Dispatch<IFACE, typename L4::Kobject_typeid<IFACE>::Iface_list::type>
469 {};
470 
471 } // namespace Detail
472 
473 template<typename EPIFACE>
474 struct Dispatch : Detail::Dispatch<typename EPIFACE::Interface>
475 {};
476 
477 } // namespace Ipc
478 
479 
480 template<typename Derived, typename IFACE, typename BASE = L4::Epiface,
481  bool = cxx::is_polymorphic<BASE>::value>
482 struct Epiface_t : Epiface_t0<IFACE, BASE>
483 {
484  l4_msgtag_t
485  dispatch(l4_msgtag_t tag, unsigned rights, l4_utcb_t *utcb) final
486  {
487  typedef Ipc::Dispatch<Derived> Dispatch;
488  return Dispatch::f(static_cast<Derived*>(this), tag, rights, utcb);
489  }
490 };
491 
492 template<typename Derived, typename IFACE, typename BASE>
493 struct Epiface_t<Derived, IFACE, BASE, false> : Epiface_t0<IFACE, BASE>
494 {
495  l4_msgtag_t
496  dispatch(l4_msgtag_t tag, unsigned rights, l4_utcb_t *utcb)
497  {
498  typedef Ipc::Dispatch<Derived> Dispatch;
499  return Dispatch::f(static_cast<Derived*>(this), tag, rights, utcb);
500  }
501 };
502 
503 /**
504  * \ingroup cxx_ipc_server
505  * \brief This registry returns the corresponding server object
506  * based on the label of an Ipc_gate.
507  */
508 class Basic_registry
509 {
510 public:
511  typedef Epiface Value;
512  /**
513  * \brief Get the server object for an Ipc_gate label.
514  * \param label The label usually stored in an Ipc_gate.
515  * \return A pointer to the Epiface identified by the given label.
516  */
517  static Value *find(l4_umword_t label)
518  { return reinterpret_cast<Value*>(label & ~3UL); }
519 
520  /**
521  * \brief The dispatch function called by the server loop.
522  *
523  * This function forwards the message to the server object identified by the
524  * given \a label.
525  *
526  * \param tag The message tag used for the invocation.
527  * \param label The label used to find the object including the rights bits
528  * of the invoked capability.
529  * \param utcb The UTCB used for the invocation.
530  * \return The return code from the object's dispatch function or -L4_ENOENT
531  * if the object does not exist.
532  */
533  static l4_msgtag_t dispatch(l4_msgtag_t tag, l4_umword_t label,
534  l4_utcb_t *utcb)
535  {
536  return find(label)->dispatch(tag, label, utcb);
537  }
538 };
539 
540 
541 } // namespace L4
542