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 * License: see LICENSE.spdx (in this directory or the directories above)
6 */
7#pragma once
8#pragma GCC system_header
9
10#include <l4/sys/cxx/ipc_basics>
11#include <l4/sys/cxx/ipc_types>
12#include <l4/sys/__typeinfo.h>
13
22
219
220// TODO: add some more documentation
221namespace L4 { namespace Ipc {
222
240{
241 enum { Is_call = true };
242 enum { Rights = 0 };
243 static l4_timeout_t timeout() { return L4_IPC_NEVER; }
244};
245
250{
251 static l4_timeout_t timeout() { return L4_IPC_SEND_TIMEOUT_0; }
252};
253
269template<unsigned RIGHTS>
271{
272 enum { Rights = RIGHTS };
273};
274
288{
289 enum { Is_call = false };
290 enum { Rights = 0 };
291 static l4_timeout_t timeout() { return L4_IPC_NEVER; }
292};
293
294namespace Msg {
295
306template<typename OP, typename CLASS, typename SIG, typename FLAGS = Call>
307struct L4_EXPORT Rpc_inline_call;
308
313template<typename OP, typename CLASS, typename FLAGS, typename R,
314 typename ...ARGS>
315struct L4_EXPORT Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>
316{
317 template<typename T> struct Result { typedef T result_type; };
318 enum
319 {
320 Return_tag = L4::Types::Same<R, l4_msgtag_t>::value
321 };
322
324 typedef Rpc_inline_call type;
326 typedef OP op_type;
328 typedef CLASS class_type;
330 typedef typename Result<R>::result_type result_type;
332 typedef R ipc_type (ARGS...);
334 typedef result_type func_type (typename _Elem<ARGS>::arg_type...);
335
337 typedef FLAGS flags_type;
338
339 template<typename RES>
340 static typename L4::Types::Enable_if< Return_tag, RES >::type
341 return_err(l4_ret_t err) noexcept { return l4_msgtag(err, 0, 0, 0); }
342
343 template<typename RES>
344 static typename L4::Types::Enable_if< Return_tag, RES >::type
345 return_ipc_err(l4_msgtag_t tag, l4_utcb_t const *) noexcept { return tag; }
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; }
350
351 template<typename RES>
352 static typename L4::Types::Enable_if< !Return_tag, RES >::type
353 return_err(long err) noexcept { return err; }
354
355 template<typename RES>
356 static typename L4::Types::Enable_if< !Return_tag, RES >::type
357 return_ipc_err(l4_msgtag_t, l4_utcb_t *utcb) noexcept
358 { return l4_ipc_to_errno(l4_ipc_error_code(utcb)); }
359
360 template<typename RES>
361 static typename L4::Types::Enable_if< !Return_tag, RES >::type
362 return_code(l4_msgtag_t tag) noexcept { return tag.label(); }
363
364 static R call(L4::Cap<class_type> cap,
365 typename _Elem<ARGS>::arg_type ...a,
366 l4_utcb_t *utcb = l4_utcb()) noexcept;
367};
368
373template<typename OP, typename CLASS, typename SIG, typename FLAGS = Call>
374struct L4_EXPORT Rpc_call;
375
383template<typename IPC, typename SIG> struct _Call;
384
386template<typename IPC, typename R, typename ...ARGS>
387struct _Call<IPC, R (ARGS...)>
388{
389public:
390 typedef typename IPC::class_type class_type;
391 typedef typename IPC::result_type result_type;
392
393private:
394 L4::Cap<class_type> cap() const noexcept
395 {
396 return L4::Cap<class_type>(reinterpret_cast<l4_cap_idx_t>(this)
397 & L4_CAP_MASK);
398 }
399
400public:
402 result_type operator () (ARGS ...a, l4_utcb_t *utcb = l4_utcb()) const noexcept
403 { return IPC::call(cap(), a..., utcb); }
404};
405
412template<typename IPC> struct Call : _Call<IPC, typename IPC::func_type> {};
413
418template<typename OP,
419 typename CLASS,
420 typename FLAGS,
421 typename R,
422 typename ...ARGS>
423struct L4_EXPORT Rpc_call<OP, CLASS, R (ARGS...), FLAGS> :
424 Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>
425{
426 static R call(L4::Cap<CLASS> cap,
427 typename _Elem<ARGS>::arg_type ...a,
428 l4_utcb_t *utcb = l4_utcb()) noexcept;
429};
430
431#define L4_INLINE_RPC_SRV_FORWARD(name) \
432 template<typename OBJ> struct fwd \
433 { \
434 OBJ *o; \
435 fwd(OBJ *o) noexcept : o(o) {} \
436 template<typename ...ARGS> \
437 decltype(auto) call(ARGS ...a) noexcept(noexcept(o->op_##name(a...))) \
438 { return o->op_##name(a...); } \
439 }
440
441
454#define L4_INLINE_RPC_NF(res, name, args...) \
455 struct name##_t : L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> \
456 { \
457 typedef L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> type; \
458 L4_INLINE_RPC_SRV_FORWARD(name); \
459 }
460
467#define L4_INLINE_RPC_NF_OP(op, res, name, args...) \
468 struct name##_t : L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> \
469 { \
470 typedef L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args> type; \
471 enum { Opcode = (op) }; \
472 L4_INLINE_RPC_SRV_FORWARD(name); \
473 }
474
475#ifdef DOXYGEN
483#define L4_INLINE_RPC(res, name, args, attr...) res name args
484#else
485#define L4_INLINE_RPC(res, name, args...) \
486 L4_INLINE_RPC_NF(res, name, args); L4::Ipc::Msg::Call<name##_t> name
487#endif
488
489#ifdef DOXYGEN
498#define L4_INLINE_RPC_OP(op, res, name, args, attr...) res name args
499#else
500#define L4_INLINE_RPC_OP(op, res, name, args...) \
501 L4_INLINE_RPC_NF_OP(op, res, name, args); L4::Ipc::Msg::Call<name##_t> name
502#endif
503
511#define L4_RPC_NF(res, name, args...) \
512 struct name##_t : L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> \
513 { \
514 typedef L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> type; \
515 L4_INLINE_RPC_SRV_FORWARD(name); \
516 }
517
526#define L4_RPC_NF_OP(op, res, name, args...) \
527 struct name##_t : L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> \
528 { \
529 typedef L4::Ipc::Msg::Rpc_call<name##_t, Class, res args> type; \
530 enum { Opcode = (op) }; \
531 L4_INLINE_RPC_SRV_FORWARD(name); \
532 }
533
534#ifdef DOXYGEN
542#define L4_RPC(res, name, args, attr...) res name args
543#else
544#define L4_RPC(res, name, args...) \
545 L4_RPC_NF(res, name, args); L4::Ipc::Msg::Call<name##_t> name
546#endif
547
548#ifdef DOXYGEN
557#define L4_RPC_OP(op, res, name, args, attr...) res name args
558#else
559#define L4_RPC_OP(op, res, name, args...) \
560 L4_RPC_NF_OP(op, res, name, args); L4::Ipc::Msg::Call<name##_t> name
561#endif
562
563
568namespace Detail {
569
573template<typename ...ARGS>
574struct Buf
575{
576public:
577 template<typename DIR>
578 static constexpr int write(char *, int offset, int) noexcept
579 { return offset; }
580
581 template<typename DIR>
582 static constexpr int read(char *, int offset, int, l4_ret_t) noexcept
583 { return offset; }
584
585 typedef void Base;
586};
587
588template<typename A, typename ...M>
589struct Buf<A, M...> : Buf<M...>
590{
591 typedef Buf<M...> Base;
592
593 typedef Clnt_xmit<A> xmit;
594 typedef typename _Elem<A>::arg_type arg_type;
595 typedef Detail::_Plain<arg_type> plain;
596
597 template<typename DIR>
598 static int
599 write(char *base, int offset, int limit,
600 arg_type a, typename _Elem<M>::arg_type ...m) noexcept
601 {
602 offset = xmit::to_msg(base, offset, limit, plain::deref(a),
603 typename DIR::dir(), typename DIR::cls());
604 return Base::template write<DIR>(base, offset, limit, m...);
605 }
606
607 template<typename DIR>
608 static int
609 read(char *base, int offset, int limit, l4_ret_t ret,
610 arg_type a, typename _Elem<M>::arg_type ...m) noexcept
611 {
612 int r = xmit::from_msg(base, offset, limit, ret, plain::deref(a),
613 typename DIR::dir(), typename DIR::cls());
614 if (L4_LIKELY(r >= 0))
615 return Base::template read<DIR>(base, r, limit, ret, m...);
616
617 if (_Elem<A>::Is_optional)
618 return Base::template read<DIR>(base, offset, limit, ret, m...);
619
620 return r;
621 }
622};
623
624template <typename ...ARGS> struct _Part
625{
627 typedef Buf<ARGS...> Data;
628
629 template<typename DIR>
630 static int write(void *b, int offset, int limit,
631 typename _Elem<ARGS>::arg_type ...m) noexcept
632 {
633 char *buf = static_cast<char *>(b);
634 int r = Data::template write<DIR>(buf, offset, limit, m...);
635 if (L4_LIKELY(r >= offset))
636 return r - offset;
637 return r;
638 }
639
640 template<typename DIR>
641 static int read(void *b, int offset, int limit, l4_ret_t ret,
642 typename _Elem<ARGS>::arg_type ...m) noexcept
643 {
644 char *buf = static_cast<char *>(b);
645 int r = Data::template read<DIR>(buf, offset, limit, ret, m...);
646 if (L4_LIKELY(r >= offset))
647 return r - offset;
648 return r;
649 }
650};
651
658template<typename IPC_TYPE, typename OPCODE = void>
659struct Part;
660
661// The version without an op-code
662template<typename R, typename ...ARGS>
663struct Part<R (ARGS...), void> : _Part<ARGS...>
664{
666 typedef Buf<ARGS...> Data;
667
668 // write arguments, skipping the dummy opcode
669 template<typename DIR>
670 static int write_op(void *b, int offset, int limit,
671 int /*placeholder for op*/,
672 typename _Elem<ARGS>::arg_type ...m) noexcept
673 {
674 char *buf = static_cast<char *>(b);
675 int r = Data::template write<DIR>(buf, offset, limit, m...);
676 if (L4_LIKELY(r >= offset))
677 return r - offset;
678 return r;
679 }
680};
681
682// Message part with additional opcode
683template<typename OPCODE, typename R, typename ...ARGS>
684struct Part<R (ARGS...), OPCODE> : _Part<ARGS...>
685{
686 typedef OPCODE opcode_type;
688 typedef Buf<opcode_type, ARGS...> Data;
689
690 // write arguments, including the opcode
691 template<typename DIR>
692 static int write_op(void *b, int offset, int limit,
693 opcode_type op, typename _Elem<ARGS>::arg_type ...m) noexcept
694 {
695 char *buf = static_cast<char *>(b);
696 int r = Data::template write<DIR>(buf, offset, limit, op, m...);
697 if (L4_LIKELY(r >= offset))
698 return r - offset;
699 return r;
700 }
701};
702
703
704} // namespace Detail
705
706//----------------------------------------------------
707// Implementation of the RPC call
708// TODO: Add support for timeout via special RPC argument
709// TODO: Add support for passing the UTCB pointer as argument
710//
711template<typename OP, typename CLASS, typename FLAGS, typename R,
712 typename ...ARGS>
713inline R
714Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>::
715 call(L4::Cap<CLASS> cap,
716 typename _Elem<ARGS>::arg_type ...a,
717 l4_utcb_t *utcb) noexcept
718{
719 using namespace Ipc::Msg;
720
721 typedef typename Kobject_typeid<CLASS>::Iface::Rpcs Rpcs;
722 typedef typename Rpcs::template Rpc<OP> Opt;
723 typedef Detail::Part<ipc_type, typename Rpcs::opcode_type> Args;
724
725 l4_msg_regs_t *mrs = l4_utcb_mr_u(utcb);
726
727 // handle in-data part of the arguments
728 int send_bytes =
729 Args::template write_op<Do_in_data>(mrs->mr, 0, Mr_bytes,
730 Opt::Opcode, a...);
731
732 if (L4_UNLIKELY(send_bytes < 0))
733 return return_err<R>(send_bytes);
734
735 send_bytes = align_to<l4_umword_t>(send_bytes);
736 int const send_words = send_bytes / Word_bytes;
737 // write the in-items part of the message if there is one
738 int item_bytes =
739 Args::template write<Do_in_items>(&mrs->mr[send_words], 0,
740 Mr_bytes - send_bytes, a...);
741
742 if (L4_UNLIKELY(item_bytes < 0))
743 return return_err<R>(item_bytes);
744
745 int send_items = item_bytes / Item_bytes;
746
747 {
748 // setup the receive buffers for the RPC call
749 l4_buf_regs_t *brs = l4_utcb_br_u(utcb);
750 // XXX: we currently support only one type of receive buffers per call
751 brs->bdr = 0; // we always start at br[0]
752
753 // the limit leaves us at least one register for the zero terminator
754 // add the buffers given as arguments to the buffer registers
755 int bytes =
756 Args::template write<Do_rcv_buffers>(brs->br, 0, Br_bytes - Word_bytes,
757 a...);
758
759 if (L4_UNLIKELY(bytes < 0))
760 return return_err<R>(bytes);
761
762 brs->br[bytes / Word_bytes] = 0;
763 }
764
765
766 // here we do the actual IPC ---------------------------------
767 l4_msgtag_t t;
768 t = l4_msgtag(CLASS::Protocol, send_words, send_items, 0);
769 // do the call (Q: do we need support for timeouts?)
770 if (flags_type::Is_call)
771 t = l4_ipc_call(cap.cap(), utcb, t, flags_type::timeout());
772 else
773 {
774 t = l4_ipc_send(cap.cap(), utcb, t, flags_type::timeout());
775 if (L4_UNLIKELY(t.has_error()))
776 return return_ipc_err<R>(t, utcb);
777
778 return return_code<R>(l4_msgtag(0, 0, 0, t.flags()));
779 }
780
781 // unmarshalling starts here ---------------------------------
782
783 // bail out early in the case of an IPC error
784 if (L4_UNLIKELY(t.has_error()))
785 return return_ipc_err<R>(t, utcb);
786
787 // take the label as return value
788 l4_ret_t r = t.label();
789
790 // bail out on negative error codes too
791 if (L4_UNLIKELY(r < 0))
792 return return_err<R>(r);
793
794 int const rcv_bytes = t.words() * Word_bytes;
795
796 // read the static out-data values to the arguments
797 int err = Args::template read<Do_out_data>(mrs->mr, 0, rcv_bytes, r, a...);
798
799 int const item_limit = t.items() * Item_bytes;
800
801 if (L4_UNLIKELY(err < 0 || item_limit > Mr_bytes))
802 return return_err<R>(-L4_EMSGTOOSHORT);
803
804 // read the static out-items to the arguments
805 err = Args::template read<Do_out_items>(&mrs->mr[t.words()], 0, item_limit,
806 r, a...);
807
808 if (L4_UNLIKELY(err < 0))
809 return return_err<R>(-L4_EMSGTOOSHORT);
810
811 return return_code<R>(t);
812}
813
814} // namespace Msg
815} // namespace Ipc
816} // namespace L4
Type information handling.
l4_cap_idx_t cap() const noexcept
Return capability selector.
Definition capability.h:49
unsigned long l4_cap_idx_t
Capability selector type.
Definition types.h:352
#define L4_CAP_MASK
Mask to get only the relevant bits of an l4_cap_idx_t.
Definition consts.h:150
@ L4_EMSGTOOSHORT
Message too short.
Definition err.h:57
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:590
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:569
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:662
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:421
#define L4_IPC_SEND_TIMEOUT_0
0 send timeout
Definition __timeout.h:78
#define L4_IPC_NEVER
never timeout
Definition __timeout.h:76
struct l4_utcb_t l4_utcb_t
Opaque type for the UTCB.
Definition utcb.h:56
l4_utcb_t * l4_utcb(void) L4_NOTHROW L4_PURE
Get the UTCB address.
Definition utcb.h:349
struct l4_buf_regs_t l4_buf_regs_t
Encapsulation of the buffer-registers block in the UTCB.
union l4_msg_regs_t l4_msg_regs_t
Encapsulation of the message-register block in the UTCB.
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:289
#define L4_EXPORT
Attribute to mark functions, variables, and data types as being exported from a library.
Definition compiler.h:214
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:288
L4_CONSTEXPR l4_ret_t 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:565
l4_int16_t l4_ret_t
Return value of an IPC call as well as an RPC call.
Definition types.h:28
IPC Message related functionality.
Definition ipc_array:154
@ Item_bytes
number of bytes for one message item
Definition ipc_basics:92
@ Word_bytes
number of bytes for one message word
Definition ipc_basics:88
IPC related functionality.
Definition ipc_array:13
L4 low-level kernel interface.
RPC attribute for an RPC call with required rights.
Definition ipc_iface:271
RPC attribute for an RPC call, with zero send timeout.
Definition ipc_iface:250
RPC attribute for a standard RPC call.
Definition ipc_iface:240
RPC attribute for a send-only RPC.
Definition ipc_iface:288
l4_umword_t br[L4_UTCB_GENERIC_BUFFERS_SIZE]
Buffer registers.
Definition utcb.h:153
l4_umword_t bdr
Buffer descriptor.
Definition utcb.h:150
long label() const L4_NOTHROW
Get the protocol value.
Definition types.h:270
bool has_error() const L4_NOTHROW
Test if flags indicate an error.
Definition types.h:299
unsigned words() const L4_NOTHROW
Get the number of untyped words.
Definition types.h:274
unsigned items() const L4_NOTHROW
Get the number of typed items.
Definition types.h:276
unsigned flags() const L4_NOTHROW
Get the flags value.
Definition types.h:283
l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]
Message registers.
Definition utcb.h:134
Timeout pair.
Definition __timeout.h:53