L4Re - L4 Runtime Environment
ipc_iface
Go to the documentation of this file.
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /*
3  * (c) 2014 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 <l4/sys/cxx/ipc_basics>
22 #include <l4/sys/cxx/ipc_types>
23 #include <l4/sys/__typeinfo.h>
24 
207 // TODO: add some more documentation
208 namespace L4 { namespace Ipc {
209 
226 struct L4_EXPORT Call
227 {
228  enum { Is_call = true };
229  enum { Rights = 0 };
230  static l4_timeout_t timeout() { return L4_IPC_NEVER; }
231 };
232 
236 struct L4_EXPORT Call_zero_send_timeout : Call
237 {
238  static l4_timeout_t timeout() { return L4_IPC_SEND_TIMEOUT_0; }
239 };
240 
256 template<unsigned RIGHTS>
257 struct L4_EXPORT Call_t : Call
258 {
259  enum { Rights = RIGHTS };
260 };
261 
274 struct L4_EXPORT Send_only
275 {
276  enum { Is_call = false };
277  enum { Rights = 0 };
278  static l4_timeout_t timeout() { return L4_IPC_NEVER; }
279 };
280 
281 namespace Msg {
282 
293 template<typename OP, typename CLASS, typename SIG, typename FLAGS = Call>
294 struct L4_EXPORT Rpc_inline_call;
295 
300 template<typename OP, typename CLASS, typename FLAGS, typename R,
301  typename ...ARGS>
302 struct L4_EXPORT Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>
303 {
304  template<typename T> struct Result { typedef T result_type; };
305  enum
306  {
308  };
309 
311  typedef Rpc_inline_call type;
313  typedef OP op_type;
315  typedef CLASS class_type;
317  typedef typename Result<R>::result_type result_type;
319  typedef R ipc_type (ARGS...);
321  typedef result_type func_type (typename _Elem<ARGS>::arg_type...);
322 
324  typedef FLAGS flags_type;
325 
326  template<typename RES>
327  static typename L4::Types::Enable_if< Return_tag, RES >::type
328  return_err(long err) noexcept { return l4_msgtag(err, 0, 0, 0); }
329 
330  template<typename RES>
331  static typename L4::Types::Enable_if< Return_tag, RES >::type
332  return_ipc_err(l4_msgtag_t tag, l4_utcb_t const *) noexcept { return tag; }
333 
334  template<typename RES>
335  static typename L4::Types::Enable_if< Return_tag, RES >::type
336  return_code(l4_msgtag_t tag) noexcept { return tag; }
337 
338  template<typename RES>
339  static typename L4::Types::Enable_if< !Return_tag, RES >::type
340  return_err(long err) noexcept { return err; }
341 
342  template<typename RES>
343  static typename L4::Types::Enable_if< !Return_tag, RES >::type
344  return_ipc_err(l4_msgtag_t, l4_utcb_t *utcb) noexcept
345  { return l4_ipc_to_errno(l4_ipc_error_code(utcb)); }
346 
347  template<typename RES>
348  static typename L4::Types::Enable_if< !Return_tag, RES >::type
349  return_code(l4_msgtag_t tag) noexcept { return tag.label(); }
350 
351  static R call(L4::Cap<class_type> cap,
352  typename _Elem<ARGS>::arg_type ...a,
353  l4_utcb_t *utcb = l4_utcb()) noexcept;
354 };
355 
360 template<typename OP, typename CLASS, typename SIG, typename FLAGS = Call>
361 struct L4_EXPORT Rpc_call;
362 
370 template<typename IPC, typename SIG> struct _Call;
371 
373 template<typename IPC, typename R, typename ...ARGS>
374 struct _Call<IPC, R (ARGS...)>
375 {
376 public:
377  typedef typename IPC::class_type class_type;
378  typedef typename IPC::result_type result_type;
379 
380 private:
381  L4::Cap<class_type> cap() const noexcept
382  {
383  return L4::Cap<class_type>(reinterpret_cast<l4_cap_idx_t>(this)
384  & L4_CAP_MASK);
385  }
386 
387 public:
389  result_type operator () (ARGS ...a, l4_utcb_t *utcb = l4_utcb()) const noexcept
390  { return IPC::call(cap(), a..., utcb); }
391 };
392 
399 template<typename IPC> struct Call : _Call<IPC, typename IPC::func_type> {};
400 
405 template<typename OP,
406  typename CLASS,
407  typename FLAGS,
408  typename R,
409  typename ...ARGS>
410 struct L4_EXPORT Rpc_call<OP, CLASS, R (ARGS...), FLAGS> :
411  Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>
412 {
413  static R call(L4::Cap<CLASS> cap,
414  typename _Elem<ARGS>::arg_type ...a,
415  l4_utcb_t *utcb = l4_utcb()) noexcept;
416 };
417 
418 #define L4_INLINE_RPC_SRV_FORWARD(name) \
419  template<typename OBJ> struct fwd \
420  { \
421  OBJ *o; \
422  fwd(OBJ *o) noexcept : o(o) {} \
423  template<typename ...ARGS> long call(ARGS ...a) noexcept(noexcept(o->op_##name(a...))) \
424  { return o->op_##name(a...); } \
425  }
426 
427 
440 #define L4_INLINE_RPC_NF(res, name, args...) \
441  struct name##_t : L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> \
442  { \
443  typedef L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> type; \
444  L4_INLINE_RPC_SRV_FORWARD(name); \
445  }
446 
453 #define L4_INLINE_RPC_NF_OP(op, res, name, args...) \
454  struct name##_t : L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> \
455  { \
456  typedef L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> type; \
457  enum { Opcode = (op) }; \
458  L4_INLINE_RPC_SRV_FORWARD(name); \
459  }
460 
461 #ifdef DOXYGEN
462 
469 #define L4_INLINE_RPC(res, name, args, attr...) res name args
470 #else
471 #define L4_INLINE_RPC(res, name, args...) \
472  L4_INLINE_RPC_NF(res, name, args); L4::Ipc::Msg::Call<name##_t> name
473 #endif
474 
475 #ifdef DOXYGEN
476 
484 #define L4_INLINE_RPC_OP(op, res, name, args, attr...) res name args
485 #else
486 #define L4_INLINE_RPC_OP(op, res, name, args...) \
487  L4_INLINE_RPC_NF_OP(op, res, name, args); L4::Ipc::Msg::Call<name##_t> name
488 #endif
489 
497 #define L4_RPC_NF(res, name, args...) \
498  struct name##_t : L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> \
499  { \
500  typedef L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> type; \
501  L4_INLINE_RPC_SRV_FORWARD(name); \
502  }
503 
512 #define L4_RPC_NF_OP(op, res, name, args...) \
513  struct name##_t : L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> \
514  { \
515  typedef L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> type; \
516  enum { Opcode = (op) }; \
517  L4_INLINE_RPC_SRV_FORWARD(name); \
518  }
519 
520 #ifdef DOXYGEN
521 
528 #define L4_RPC(res, name, args, attr...) res name args
529 #else
530 #define L4_RPC(res, name, args...) \
531  L4_RPC_NF(res, name, args); L4::Ipc::Msg::Call<name##_t> name
532 #endif
533 
534 #ifdef DOXYGEN
535 
543 #define L4_RPC_OP(op, res, name, args, attr...) res name args
544 #else
545 #define L4_RPC_OP(op, res, name, args...) \
546  L4_RPC_NF_OP(op, res, name, args); L4::Ipc::Msg::Call<name##_t> name
547 #endif
548 
549 
554 namespace Detail {
555 
559 template<typename ...ARGS>
560 struct Buf
561 {
562 public:
563  template<typename DIR>
564  static constexpr int write(char *, int offset, int) noexcept
565  { return offset; }
566 
567  template<typename DIR>
568  static constexpr int read(char *, int offset, int, long) noexcept
569  { return offset; }
570 
571  typedef void Base;
572 };
573 
574 template<typename A, typename ...M>
575 struct Buf<A, M...> : Buf<M...>
576 {
577  typedef Buf<M...> Base;
578 
579  typedef Clnt_xmit<A> xmit;
580  typedef typename _Elem<A>::arg_type arg_type;
581  typedef Detail::_Plain<arg_type> plain;
582 
583  template<typename DIR>
584  static int
585  write(char *base, int offset, int limit,
586  arg_type a, typename _Elem<M>::arg_type ...m) noexcept
587  {
588  offset = xmit::to_msg(base, offset, limit, plain::deref(a),
589  typename DIR::dir(), typename DIR::cls());
590  return Base::template write<DIR>(base, offset, limit, m...);
591  }
592 
593  template<typename DIR>
594  static int
595  read(char *base, int offset, int limit, long ret,
596  arg_type a, typename _Elem<M>::arg_type ...m) noexcept
597  {
598  int r = xmit::from_msg(base, offset, limit, ret, plain::deref(a),
599  typename DIR::dir(), typename DIR::cls());
600  if (L4_LIKELY(r >= 0))
601  return Base::template read<DIR>(base, r, limit, ret, m...);
602 
603  if (_Elem<A>::Is_optional)
604  return Base::template read<DIR>(base, offset, limit, ret, m...);
605 
606  return r;
607  }
608 };
609 
610 template <typename ...ARGS> struct _Part
611 {
613  typedef Buf<ARGS...> Data;
614 
615  template<typename DIR>
616  static int write(void *b, int offset, int limit,
617  typename _Elem<ARGS>::arg_type ...m) noexcept
618  {
619  int r = Data::template write<DIR>((char *)b, offset, limit, m...);
620  if (L4_LIKELY(r >= offset))
621  return r - offset;
622  return r;
623  }
624 
625  template<typename DIR>
626  static int read(void *b, int offset, int limit, long ret,
627  typename _Elem<ARGS>::arg_type ...m) noexcept
628  {
629  int r = Data::template read<DIR>((char *)b, offset, limit, ret, m...);
630  if (L4_LIKELY(r >= offset))
631  return r - offset;
632  return r;
633  }
634 };
635 
642 template<typename IPC_TYPE, typename OPCODE = void>
643 struct Part;
644 
645 // The version without an op-code
646 template<typename R, typename ...ARGS>
647 struct Part<R (ARGS...), void> : _Part<ARGS...>
648 {
650  typedef Buf<ARGS...> Data;
651 
652  // write arguments, skipping the dummy opcode
653  template<typename DIR>
654  static int write_op(void *b, int offset, int limit,
655  int /*placeholder for op*/,
656  typename _Elem<ARGS>::arg_type ...m) noexcept
657  {
658  int r = Data::template write<DIR>((char *)b, offset, limit, m...);
659  if (L4_LIKELY(r >= offset))
660  return r - offset;
661  return r;
662  }
663 };
664 
665 // Message part with additional opcode
666 template<typename OPCODE, typename R, typename ...ARGS>
667 struct Part<R (ARGS...), OPCODE> : _Part<ARGS...>
668 {
669  typedef OPCODE opcode_type;
671  typedef Buf<opcode_type, ARGS...> Data;
672 
673  // write arguments, including the opcode
674  template<typename DIR>
675  static int write_op(void *b, int offset, int limit,
676  opcode_type op, typename _Elem<ARGS>::arg_type ...m) noexcept
677  {
678  int r = Data::template write<DIR>((char *)b, offset, limit, op, m...);
679  if (L4_LIKELY(r >= offset))
680  return r - offset;
681  return r;
682  }
683 };
684 
685 
686 } // namespace Detail
687 
688 //----------------------------------------------------
689 // Implementation of the RPC call
690 // TODO: Add support for timeout via special RPC argument
691 // TODO: Add support for passing the UTCB pointer as argument
692 //
693 template<typename OP, typename CLASS, typename FLAGS, typename R,
694  typename ...ARGS>
695 inline R
696 Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>::
697  call(L4::Cap<CLASS> cap,
698  typename _Elem<ARGS>::arg_type ...a,
699  l4_utcb_t *utcb) noexcept
700 {
701  using namespace Ipc::Msg;
702 
703  typedef typename Kobject_typeid<CLASS>::Iface::Rpcs Rpcs;
704  typedef typename Rpcs::template Rpc<OP> Opt;
705  typedef Detail::Part<ipc_type, typename Rpcs::opcode_type> Args;
706 
707  l4_msg_regs_t *mrs = l4_utcb_mr_u(utcb);
708 
709  // handle in-data part of the arguments
710  int send_bytes =
711  Args::template write_op<Do_in_data>(mrs->mr, 0, Mr_bytes,
712  Opt::Opcode, a...);
713 
714  if (L4_UNLIKELY(send_bytes < 0))
715  return return_err<R>(send_bytes);
716 
717  send_bytes = align_to<l4_umword_t>(send_bytes);
718  int const send_words = send_bytes / Word_bytes;
719  // write the in-items part of the message if there is one
720  int item_bytes =
721  Args::template write<Do_in_items>(&mrs->mr[send_words], 0,
722  Mr_bytes - send_bytes, a...);
723 
724  if (L4_UNLIKELY(item_bytes < 0))
725  return return_err<R>(item_bytes);
726 
727  int send_items = item_bytes / Item_bytes;
728 
729  {
730  // setup the receive buffers for the RPC call
731  l4_buf_regs_t *brs = l4_utcb_br_u(utcb);
732  // XXX: we currently support only one type of receive buffers per call
733  brs->bdr = 0; // we always start at br[0]
734 
735  // the limit leaves us at least one register for the zero terminator
736  // add the buffers given as arguments to the buffer registers
737  int bytes =
738  Args::template write<Do_rcv_buffers>(brs->br, 0, Br_bytes - Word_bytes,
739  a...);
740 
741  if (L4_UNLIKELY(bytes < 0))
742  return return_err<R>(bytes);
743 
744  brs->br[bytes / Word_bytes] = 0;
745  }
746 
747 
748  // here we do the actual IPC ---------------------------------
749  l4_msgtag_t t;
750  t = l4_msgtag(CLASS::Protocol, send_words, send_items, 0);
751  // do the call (Q: do we need support for timeouts?)
752  if (flags_type::Is_call)
753  t = l4_ipc_call(cap.cap(), utcb, t, flags_type::timeout());
754  else
755  {
756  t = l4_ipc_send(cap.cap(), utcb, t, flags_type::timeout());
757  if (L4_UNLIKELY(t.has_error()))
758  return return_ipc_err<R>(t, utcb);
759 
760  return return_code<R>(l4_msgtag(0, 0, 0, t.flags()));
761  }
762 
763  // unmarshalling starts here ---------------------------------
764 
765  // bail out early in the case of an IPC error
766  if (L4_UNLIKELY(t.has_error()))
767  return return_ipc_err<R>(t, utcb);
768 
769  // take the label as return value
770  long r = t.label();
771 
772  // bail out on negative error codes too
773  if (L4_UNLIKELY(r < 0))
774  return return_err<R>(r);
775 
776  int const rcv_bytes = t.words() * Word_bytes;
777 
778  // read the static out-data values to the arguments
779  int err = Args::template read<Do_out_data>(mrs->mr, 0, rcv_bytes, r, a...);
780 
781  int const item_limit = t.items() * Item_bytes;
782 
783  if (L4_UNLIKELY(err < 0 || item_limit > Mr_bytes))
784  return return_err<R>(-L4_EMSGTOOSHORT);
785 
786  // read the static out-items to the arguments
787  err = Args::template read<Do_out_items>(&mrs->mr[t.words()], 0, item_limit,
788  r, a...);
789 
790  if (L4_UNLIKELY(err < 0))
791  return return_err<R>(-L4_EMSGTOOSHORT);
792 
793  return return_code<R>(t);
794 }
795 
796 } // namespace Msg
797 } // namesapce Ipc
798 } // namespace L4
799 
800 
L4::Cap
C++ interface for capabilities.
Definition: capability.h:219
l4_utcb
l4_utcb_t * l4_utcb(void) L4_NOTHROW L4_PURE
Get the UTCB address.
Definition: utcb.h:340
l4_cap_idx_t
unsigned long l4_cap_idx_t
L4 Capability selector Type.
Definition: types.h:342
L4::Opcode
int Opcode
Data type for RPC opcodes.
Definition: __typeinfo.h:47
L4::Ipc::Call
RPC attribute for a standard RPC call.
Definition: ipc_iface:227
L4::Ipc::Send_only
RPC attribute for a send-only RPC.
Definition: ipc_iface:275
l4_msgtag_t::flags
unsigned flags() const L4_NOTHROW
Get the flags value.
Definition: types.h:177
l4_msgtag
l4_msgtag_t l4_msgtag(long label, unsigned words, unsigned items, unsigned flags) L4_NOTHROW
Create a message tag from the specified values.
Definition: types.h:408
L4::Ipc::Msg::Mr_bytes
@ Mr_bytes
number of bytes available in the UTCB message registers
Definition: ipc_basics:107
l4_ipc_to_errno
long l4_ipc_to_errno(unsigned long ipc_error_code) L4_NOTHROW
Get a negative error code for the given IPC error code.
Definition: ipc.h:444
ipc_types
L4_EMSGTOOSHORT
@ L4_EMSGTOOSHORT
Message too short.
Definition: err.h:66
l4_timeout_t
Timeout pair.
Definition: __timeout.h:59
l4_msgtag_t::label
long label() const L4_NOTHROW
Get the protocol value.
Definition: types.h:164
L4::Ipc::Msg::Item_bytes
@ Item_bytes
number of bytes for one message item
Definition: ipc_basics:103
l4_msgtag_t::words
unsigned words() const L4_NOTHROW
Get the number of untyped words.
Definition: types.h:168
L4::Ipc::read
T read(Istream &s)
Read a value out of a stream.
Definition: ipc_stream:1404
l4_ipc_send
l4_msgtag_t l4_ipc_send(l4_cap_idx_t dest, l4_utcb_t *utcb, l4_msgtag_t tag, l4_timeout_t timeout) L4_NOTHROW
Send a message to an object (do not wait for a reply).
Definition: ipc.h:473
l4_msg_regs_t
Encapsulation of the message-register block in the UTCB.
Definition: utcb.h:79
l4_msgtag_t::items
unsigned items() const L4_NOTHROW
Get the number of typed items.
Definition: types.h:170
L4::Types::Same
Compare two data types for equality.
Definition: types:324
l4_buf_regs_t::bdr
l4_umword_t bdr
Buffer descriptor.
Definition: utcb.h:96
l4_msg_regs_t::mr
l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]
Message registers.
Definition: utcb.h:80
L4_UNLIKELY
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition: compiler.h:238
L4_CAP_MASK
@ L4_CAP_MASK
Mask to get only the relevant bits of an l4_cap_idx_t.
Definition: consts.h:139
L4::Ipc::Msg::Br_bytes
@ Br_bytes
number of bytes available in the UTCB buffer registers
Definition: ipc_basics:109
L4
L4 low-level kernel interface.
Definition: l4sys-l4f-groups.dox:68
l4_msgtag_t::has_error
unsigned has_error() const L4_NOTHROW
Test if flags indicate an error.
Definition: types.h:191
__typeinfo.h
Type information handling.
l4_buf_regs_t
Encapsulation of the buffer-registers block in the UTCB.
Definition: utcb.h:94
L4::Ipc::Call_t
RPC attribute for an RPC call with required rights.
Definition: ipc_iface:258
L4::Ipc::Msg::Word_bytes
@ Word_bytes
number of bytes for one message word
Definition: ipc_basics:99
l4_ipc_call
l4_msgtag_t l4_ipc_call(l4_cap_idx_t object, l4_utcb_t *utcb, l4_msgtag_t tag, l4_timeout_t timeout) L4_NOTHROW
Object call (usual invocation).
Definition: ipc.h:448
l4_ipc_error_code
int l4_ipc_error_code(l4_utcb_t *utcb) L4_NOTHROW
Get the error condition of the last invocation from the TCR.
Definition: ipc.h:532
l4_utcb_t
struct l4_utcb_t l4_utcb_t
Opaque type for the UTCB.
Definition: utcb.h:67
L4::Ipc::Call_zero_send_timeout
RPC attribute for an RPC call, with zero send timeout.
Definition: ipc_iface:237
L4_LIKELY
#define L4_LIKELY(x)
Expression is likely to execute.
Definition: compiler.h:237
l4_msgtag_t
Message tag data structure.
Definition: types.h:160
l4_buf_regs_t::br
l4_umword_t br[L4_UTCB_GENERIC_BUFFERS_SIZE]
Buffer registers.
Definition: utcb.h:99