L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
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
208namespace L4 { namespace Ipc {
209
227{
228 enum { Is_call = true };
229 enum { Rights = 0 };
230 static l4_timeout_t timeout() { return L4_IPC_NEVER; }
231};
232
237{
238 static l4_timeout_t timeout() { return L4_IPC_SEND_TIMEOUT_0; }
239};
240
256template<unsigned RIGHTS>
258{
259 enum { Rights = RIGHTS };
260};
261
275{
276 enum { Is_call = false };
277 enum { Rights = 0 };
278 static l4_timeout_t timeout() { return L4_IPC_NEVER; }
279};
280
281namespace Msg {
282
293template<typename OP, typename CLASS, typename SIG, typename FLAGS = Call>
294struct L4_EXPORT Rpc_inline_call;
295
300template<typename OP, typename CLASS, typename FLAGS, typename R,
301 typename ...ARGS>
302struct 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
360template<typename OP, typename CLASS, typename SIG, typename FLAGS = Call>
361struct L4_EXPORT Rpc_call;
362
370template<typename IPC, typename SIG> struct _Call;
371
373template<typename IPC, typename R, typename ...ARGS>
374struct _Call<IPC, R (ARGS...)>
375{
376public:
377 typedef typename IPC::class_type class_type;
378 typedef typename IPC::result_type result_type;
379
380private:
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
387public:
389 result_type operator () (ARGS ...a, l4_utcb_t *utcb = l4_utcb()) const noexcept
390 { return IPC::call(cap(), a..., utcb); }
391};
392
399template<typename IPC> struct Call : _Call<IPC, typename IPC::func_type> {};
400
405template<typename OP,
406 typename CLASS,
407 typename FLAGS,
408 typename R,
409 typename ...ARGS>
410struct 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
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
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
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
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
554namespace Detail {
555
559template<typename ...ARGS>
560struct Buf
561{
562public:
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
574template<typename A, typename ...M>
575struct 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
610template <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 char *buf = static_cast<char *>(b);
620 int r = Data::template write<DIR>(buf, offset, limit, m...);
621 if (L4_LIKELY(r >= offset))
622 return r - offset;
623 return r;
624 }
625
626 template<typename DIR>
627 static int read(void *b, int offset, int limit, long ret,
628 typename _Elem<ARGS>::arg_type ...m) noexcept
629 {
630 char *buf = static_cast<char *>(b);
631 int r = Data::template read<DIR>(buf, offset, limit, ret, m...);
632 if (L4_LIKELY(r >= offset))
633 return r - offset;
634 return r;
635 }
636};
637
644template<typename IPC_TYPE, typename OPCODE = void>
645struct Part;
646
647// The version without an op-code
648template<typename R, typename ...ARGS>
649struct Part<R (ARGS...), void> : _Part<ARGS...>
650{
652 typedef Buf<ARGS...> Data;
653
654 // write arguments, skipping the dummy opcode
655 template<typename DIR>
656 static int write_op(void *b, int offset, int limit,
657 int /*placeholder for op*/,
658 typename _Elem<ARGS>::arg_type ...m) noexcept
659 {
660 char *buf = static_cast<char *>(b);
661 int r = Data::template write<DIR>(buf, offset, limit, m...);
662 if (L4_LIKELY(r >= offset))
663 return r - offset;
664 return r;
665 }
666};
667
668// Message part with additional opcode
669template<typename OPCODE, typename R, typename ...ARGS>
670struct Part<R (ARGS...), OPCODE> : _Part<ARGS...>
671{
672 typedef OPCODE opcode_type;
674 typedef Buf<opcode_type, ARGS...> Data;
675
676 // write arguments, including the opcode
677 template<typename DIR>
678 static int write_op(void *b, int offset, int limit,
679 opcode_type op, typename _Elem<ARGS>::arg_type ...m) noexcept
680 {
681 char *buf = static_cast<char *>(b);
682 int r = Data::template write<DIR>(buf, offset, limit, op, m...);
683 if (L4_LIKELY(r >= offset))
684 return r - offset;
685 return r;
686 }
687};
688
689
690} // namespace Detail
691
692//----------------------------------------------------
693// Implementation of the RPC call
694// TODO: Add support for timeout via special RPC argument
695// TODO: Add support for passing the UTCB pointer as argument
696//
697template<typename OP, typename CLASS, typename FLAGS, typename R,
698 typename ...ARGS>
699inline R
700Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>::
701 call(L4::Cap<CLASS> cap,
702 typename _Elem<ARGS>::arg_type ...a,
703 l4_utcb_t *utcb) noexcept
704{
705 using namespace Ipc::Msg;
706
707 typedef typename Kobject_typeid<CLASS>::Iface::Rpcs Rpcs;
708 typedef typename Rpcs::template Rpc<OP> Opt;
709 typedef Detail::Part<ipc_type, typename Rpcs::opcode_type> Args;
710
711 l4_msg_regs_t *mrs = l4_utcb_mr_u(utcb);
712
713 // handle in-data part of the arguments
714 int send_bytes =
715 Args::template write_op<Do_in_data>(mrs->mr, 0, Mr_bytes,
716 Opt::Opcode, a...);
717
718 if (L4_UNLIKELY(send_bytes < 0))
719 return return_err<R>(send_bytes);
720
721 send_bytes = align_to<l4_umword_t>(send_bytes);
722 int const send_words = send_bytes / Word_bytes;
723 // write the in-items part of the message if there is one
724 int item_bytes =
725 Args::template write<Do_in_items>(&mrs->mr[send_words], 0,
726 Mr_bytes - send_bytes, a...);
727
728 if (L4_UNLIKELY(item_bytes < 0))
729 return return_err<R>(item_bytes);
730
731 int send_items = item_bytes / Item_bytes;
732
733 {
734 // setup the receive buffers for the RPC call
735 l4_buf_regs_t *brs = l4_utcb_br_u(utcb);
736 // XXX: we currently support only one type of receive buffers per call
737 brs->bdr = 0; // we always start at br[0]
738
739 // the limit leaves us at least one register for the zero terminator
740 // add the buffers given as arguments to the buffer registers
741 int bytes =
742 Args::template write<Do_rcv_buffers>(brs->br, 0, Br_bytes - Word_bytes,
743 a...);
744
745 if (L4_UNLIKELY(bytes < 0))
746 return return_err<R>(bytes);
747
748 brs->br[bytes / Word_bytes] = 0;
749 }
750
751
752 // here we do the actual IPC ---------------------------------
753 l4_msgtag_t t;
754 t = l4_msgtag(CLASS::Protocol, send_words, send_items, 0);
755 // do the call (Q: do we need support for timeouts?)
756 if (flags_type::Is_call)
757 t = l4_ipc_call(cap.cap(), utcb, t, flags_type::timeout());
758 else
759 {
760 t = l4_ipc_send(cap.cap(), utcb, t, flags_type::timeout());
761 if (L4_UNLIKELY(t.has_error()))
762 return return_ipc_err<R>(t, utcb);
763
764 return return_code<R>(l4_msgtag(0, 0, 0, t.flags()));
765 }
766
767 // unmarshalling starts here ---------------------------------
768
769 // bail out early in the case of an IPC error
770 if (L4_UNLIKELY(t.has_error()))
771 return return_ipc_err<R>(t, utcb);
772
773 // take the label as return value
774 long r = t.label();
775
776 // bail out on negative error codes too
777 if (L4_UNLIKELY(r < 0))
778 return return_err<R>(r);
779
780 int const rcv_bytes = t.words() * Word_bytes;
781
782 // read the static out-data values to the arguments
783 int err = Args::template read<Do_out_data>(mrs->mr, 0, rcv_bytes, r, a...);
784
785 int const item_limit = t.items() * Item_bytes;
786
787 if (L4_UNLIKELY(err < 0 || item_limit > Mr_bytes))
788 return return_err<R>(-L4_EMSGTOOSHORT);
789
790 // read the static out-items to the arguments
791 err = Args::template read<Do_out_items>(&mrs->mr[t.words()], 0, item_limit,
792 r, a...);
793
794 if (L4_UNLIKELY(err < 0))
795 return return_err<R>(-L4_EMSGTOOSHORT);
796
797 return return_code<R>(t);
798}
799
800} // namespace Msg
801} // namespace Ipc
802} // namespace L4
Type information handling.
l4_cap_idx_t cap() const noexcept
Return capability selector.
Definition capability.h:49
C++ interface for capabilities.
Definition capability.h:219
unsigned long l4_cap_idx_t
Capability selector type.
Definition types.h:359
@ L4_CAP_MASK
Mask to get only the relevant bits of an l4_cap_idx_t.
Definition consts.h:166
@ L4_EMSGTOOSHORT
Message too short.
Definition err.h:67
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:597
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:576
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:669
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:428
#define L4_IPC_SEND_TIMEOUT_0
0 send timeout
Definition __timeout.h:86
#define L4_IPC_NEVER
never timeout
Definition __timeout.h:84
struct l4_utcb_t l4_utcb_t
Opaque type for the UTCB.
Definition utcb.h:67
l4_utcb_t * l4_utcb(void) L4_NOTHROW L4_PURE
Get the UTCB address.
Definition utcb.h:340
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:296
#define L4_EXPORT
Attribute to mark functions, variables, and data types as being exported from a library.
Definition compiler.h:231
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:295
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:572
@ Item_bytes
number of bytes for one message item
Definition ipc_basics:103
@ Word_bytes
number of bytes for one message word
Definition ipc_basics:99
L4 low-level kernel interface.
Definition io_regblock.h:19
RPC attribute for an RPC call with required rights.
Definition ipc_iface:258
RPC attribute for an RPC call, with zero send timeout.
Definition ipc_iface:237
RPC attribute for a standard RPC call.
Definition ipc_iface:227
RPC attribute for a send-only RPC.
Definition ipc_iface:275
Compare two data types for equality.
Definition types:323
Encapsulation of the buffer-registers block in the UTCB.
Definition utcb.h:94
l4_umword_t br[L4_UTCB_GENERIC_BUFFERS_SIZE]
Buffer registers.
Definition utcb.h:99
l4_umword_t bdr
Buffer descriptor.
Definition utcb.h:96
Message tag data structure.
Definition types.h:164
long label() const L4_NOTHROW
Get the protocol value.
Definition types.h:168
unsigned has_error() const L4_NOTHROW
Test if flags indicate an error.
Definition types.h:195
unsigned words() const L4_NOTHROW
Get the number of untyped words.
Definition types.h:172
unsigned items() const L4_NOTHROW
Get the number of typed items.
Definition types.h:174
unsigned flags() const L4_NOTHROW
Get the flags value.
Definition types.h:181
Encapsulation of the message-register block in the UTCB.
Definition utcb.h:79
l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]
Message registers.
Definition utcb.h:80
Timeout pair.
Definition __timeout.h:61