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 { using result_type = T; };
318 enum
319 {
320 Return_tag = L4::Types::Same_v<R, l4_msgtag_t>
321 };
322
324 using type = Rpc_inline_call;
326 using op_type = OP;
328 using class_type = CLASS;
330 using result_type = typename Result<R>::result_type;
332 using ipc_type = R (ARGS...);
334 using func_type = result_type (typename _Elem<ARGS>::arg_type...);
335
337 using flags_type = FLAGS;
338
339 template<typename RES>
341 return_err(l4_ret_t err) noexcept { return l4_msgtag(err, 0, 0, 0); }
342
343 template<typename RES>
345 return_ipc_err(l4_msgtag_t tag, l4_utcb_t const *) noexcept { return tag; }
346
347 template<typename RES>
349 return_code(l4_msgtag_t tag) noexcept { return tag; }
350
351 template<typename RES>
353 return_err(long err) noexcept { return err; }
354
355 template<typename RES>
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>
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 using class_type = typename IPC::class_type;
391 using result_type = typename IPC::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 using type = L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args>; \
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 using type = L4::Ipc::Msg::Rpc_inline_call<name##_t, Class, res args>; \
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 using type = L4::Ipc::Msg::Rpc_call<name##_t, Class, res args>; \
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 using type = L4::Ipc::Msg::Rpc_call<name##_t, Class, res args>; \
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<Phase PHASE>
578 static constexpr int write(char *, int offset, int) noexcept
579 { return offset; }
580
581 template<Phase PHASE>
582 static constexpr int read(char *, int offset, int) noexcept
583 { return offset; }
584
585 using Base = void;
586};
587
588template<typename A, typename ...M>
589struct Buf<A, M...> : Buf<M...>
590{
591 using Base = Buf<M...>;
592
593 using xmit = Clnt_xmit<A>;
594 using arg_type = typename _Elem<A>::arg_type;
595 using plain = Detail::_Plain<arg_type>;
596 static constexpr bool Is_input = _Elem<A>::Is_input;
597 static constexpr bool Is_output = _Elem<A>::Is_output;
598
599 template<Phase PHASE>
600 static int
601 write(char *base, int offset, int limit,
602 arg_type a, typename _Elem<M>::arg_type ...m) noexcept
603 {
604 if constexpr (PHASE == Phase::Data && Is_input)
605 offset = xmit::to_msg_data(base, offset, limit, plain::deref(a));
606 else if constexpr (PHASE == Phase::Items && Is_input)
607 offset = xmit::to_msg_items(base, offset, limit, plain::deref(a));
608 else if constexpr (PHASE == Phase::Buffers && Is_output)
609 offset = xmit::to_msg_buffers(base, offset, limit, plain::deref(a));
610
611 return Base::template write<PHASE>(base, offset, limit, m...);
612 }
613
614 template<Phase PHASE>
615 static int
616 read(char *base, int offset, int limit,
617 arg_type a, typename _Elem<M>::arg_type ...m) noexcept
618 {
619 int r = offset;
620 // Read output parameters from UTCB MRs.
621 if constexpr (Is_output)
622 {
623 static_assert(PHASE == Phase::Data || PHASE == Phase::Items);
624 if constexpr (PHASE == Phase::Data)
625 r = xmit::from_msg_data(base, offset, limit, plain::deref(a));
626 else // PHASE == Phase::Items
627 r = xmit::from_msg_items(base, offset, limit, plain::deref(a));
628 }
629
630 if (L4_LIKELY(r >= 0))
631 return Base::template read<PHASE>(base, r, limit, m...);
632
633 if (_Elem<A>::Is_optional)
634 return Base::template read<PHASE>(base, offset, limit, m...);
635
636 return r;
637 }
638};
639
640template <typename ...ARGS> struct _Part
641{
643 using Data = Buf<ARGS...>;
644
645 template<Phase PHASE>
646 static int write(void *b, int offset, int limit,
647 typename _Elem<ARGS>::arg_type ...m) noexcept
648 {
649 char *buf = static_cast<char *>(b);
650 int r = Data::template write<PHASE>(buf, offset, limit, m...);
651 if (L4_LIKELY(r >= offset))
652 return r - offset;
653 return r;
654 }
655
656 template<Phase PHASE>
657 static int read(void *b, int offset, int limit,
658 typename _Elem<ARGS>::arg_type ...m) noexcept
659 {
660 char *buf = static_cast<char *>(b);
661 int r = Data::template read<PHASE>(buf, offset, limit, m...);
662 if (L4_LIKELY(r >= offset))
663 return r - offset;
664 return r;
665 }
666};
667
674template<typename IPC_TYPE, typename OPCODE = void>
675struct Part;
676
677// The version without an op-code
678template<typename R, typename ...ARGS>
679struct Part<R (ARGS...), void> : _Part<ARGS...>
680{
682 using Data = Buf<ARGS...>;
683
684 // write arguments, skipping the dummy opcode
685 static int write_op(void *b, int offset, int limit,
686 int /*placeholder for op*/,
687 typename _Elem<ARGS>::arg_type ...m) noexcept
688 {
689 char *buf = static_cast<char *>(b);
690 int r = Data::template write<Phase::Data>(buf, offset, limit, m...);
691 if (L4_LIKELY(r >= offset))
692 return r - offset;
693 return r;
694 }
695};
696
697// Message part with additional opcode
698template<typename OPCODE, typename R, typename ...ARGS>
699struct Part<R (ARGS...), OPCODE> : _Part<ARGS...>
700{
701 using opcode_type = OPCODE;
703 using Data = Buf<opcode_type, ARGS...>;
704
705 // write arguments, including the opcode
706 static int write_op(void *b, int offset, int limit,
707 opcode_type op, typename _Elem<ARGS>::arg_type ...m) noexcept
708 {
709 char *buf = static_cast<char *>(b);
710 int r = Data::template write<Phase::Data>(buf, offset, limit, op, m...);
711 if (L4_LIKELY(r >= offset))
712 return r - offset;
713 return r;
714 }
715};
716
717
718} // namespace Detail
719
720//----------------------------------------------------
721// Implementation of the RPC call
722// TODO: Add support for timeout via special RPC argument
723// TODO: Add support for passing the UTCB pointer as argument
724//
725template<typename OP, typename CLASS, typename FLAGS, typename R,
726 typename ...ARGS>
727inline R
728Rpc_inline_call<OP, CLASS, R (ARGS...), FLAGS>::
729 call(L4::Cap<CLASS> cap,
730 typename _Elem<ARGS>::arg_type ...a,
731 l4_utcb_t *utcb) noexcept
732{
733 using namespace Ipc::Msg;
734
735 using Rpcs = typename Kobject_typeid<CLASS>::Iface::Rpcs;
736 using Opt = typename Rpcs::template Rpc<OP>;
737 using Args = Detail::Part<ipc_type, typename Rpcs::opcode_type>;
738
739 l4_msg_regs_t *mrs = l4_utcb_mr_u(utcb);
740
741 // handle in-data part of the arguments
742 int send_bytes =
743 Args::write_op(mrs->mr, 0, Mr_bytes, Opt::Opcode, a...);
744
745 if (L4_UNLIKELY(send_bytes < 0))
746 return return_err<R>(send_bytes);
747
748 send_bytes = align_to<l4_umword_t>(send_bytes);
749 int const send_words = send_bytes / Word_bytes;
750 // write the in-items part of the message if there is one
751 int item_bytes =
752 Args::template write<Phase::Items>(&mrs->mr[send_words], 0,
753 Mr_bytes - send_bytes, a...);
754
755 if (L4_UNLIKELY(item_bytes < 0))
756 return return_err<R>(item_bytes);
757
758 int send_items = item_bytes / Item_bytes;
759
760 {
761 // setup the receive buffers for the RPC call
762 l4_buf_regs_t *brs = l4_utcb_br_u(utcb);
763 // XXX: we currently support only one type of receive buffers per call
764 brs->bdr = 0; // we always start at br[0]
765
766 // the limit leaves us at least one register for the zero terminator
767 // add the buffers given as arguments to the buffer registers
768 int bytes =
769 Args::template write<Phase::Buffers>(brs->br, 0, Br_bytes - Word_bytes,
770 a...);
771
772 if (L4_UNLIKELY(bytes < 0))
773 return return_err<R>(bytes);
774
775 brs->br[bytes / Word_bytes] = 0;
776 }
777
778
779 // here we do the actual IPC ---------------------------------
780 l4_msgtag_t t;
781 t = l4_msgtag(CLASS::Protocol, send_words, send_items, 0);
782 // do the call (Q: do we need support for timeouts?)
783 if (flags_type::Is_call)
784 t = l4_ipc_call(cap.cap(), utcb, t, flags_type::timeout());
785 else
786 {
787 t = l4_ipc_send(cap.cap(), utcb, t, flags_type::timeout());
788 if (L4_UNLIKELY(t.has_error()))
789 return return_ipc_err<R>(t, utcb);
790
791 return return_code<R>(l4_msgtag(0, 0, 0, t.flags()));
792 }
793
794 // unmarshalling starts here ---------------------------------
795
796 // bail out early in the case of an IPC error
797 if (L4_UNLIKELY(t.has_error()))
798 return return_ipc_err<R>(t, utcb);
799
800 // take the label as return value
801 l4_ret_t r = t.label();
802
803 // bail out on negative error codes too
804 if (L4_UNLIKELY(r < 0))
805 return return_err<R>(r);
806
807 int const rcv_bytes = t.words() * Word_bytes;
808
809 // read the static out-data values to the arguments
810 int err = Args::template read<Phase::Data>(mrs->mr, 0, rcv_bytes, a...);
811
812 int const item_limit = t.items() * Item_bytes;
813
814 if (L4_UNLIKELY(err < 0 || item_limit > Mr_bytes))
815 return return_err<R>(-L4_EMSGTOOSHORT);
816
817 // read the static out-items to the arguments
818 err = Args::template read<Phase::Items>(&mrs->mr[t.words()], 0, item_limit,
819 a...);
820
821 if (L4_UNLIKELY(err < 0))
822 return return_err<R>(-L4_EMSGTOOSHORT);
823
824 return return_code<R>(t);
825}
826
827} // namespace Msg
828} // namespace Ipc
829} // 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:372
#define L4_CAP_MASK
Mask to get only the relevant bits of an l4_cap_idx_t.
Definition consts.h:160
@ L4_EMSGTOOSHORT
Message too short.
Definition err.h:58
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:627
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:598
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:699
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:441
#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:369
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:295
#define L4_EXPORT
Attribute to mark functions, variables, and data types as being exported from a library.
Definition compiler.h:220
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:294
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:594
l4_int16_t l4_ret_t
Return value of an IPC call as well as an RPC call.
Definition types.h:29
IPC Message related functionality.
Definition ipc_array:154
@ Item_bytes
number of bytes for one message item
Definition ipc_basics:89
@ Word_bytes
number of bytes for one message word
Definition ipc_basics:85
IPC related functionality.
Definition ipc_array:13
typename Enable_if< Condition, T >::type Enable_if_t
Helper type for Enable_if.
Definition types:425
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:273
bool has_error() const L4_NOTHROW
Test if flags indicate an error.
Definition types.h:302
unsigned words() const L4_NOTHROW
Get the number of untyped words.
Definition types.h:277
unsigned items() const L4_NOTHROW
Get the number of typed items.
Definition types.h:279
unsigned flags() const L4_NOTHROW
Get the flags value.
Definition types.h:286
l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]
Message registers.
Definition utcb.h:134
Timeout pair.
Definition __timeout.h:53