8#pragma GCC system_header
10#include <l4/sys/cxx/ipc_basics>
12#include <l4/sys/cxx/limits>
23template<
typename T>
struct Sizeof {
enum { size =
sizeof(T) }; };
24template<>
struct Sizeof<void> {
enum { size = 0 }; };
29template<
typename ...>
struct Arg_pack
32 unsigned get(
char *,
unsigned offset,
unsigned)
35 unsigned reserve_data(
char *,
unsigned offset,
unsigned)
39 unsigned set(
char *,
unsigned offset,
unsigned)
42 template<
typename F,
typename ...ARGS>
43 decltype(
auto) call(F f, ARGS ...args)
44 {
return f(args...); }
46 template<
typename ...>
50 template<
typename O,
typename FUNC,
typename ...ARGS>
51 auto obj_call(O *o, ARGS ...args)
52 ->
decltype(
typename FUNC::template fwd<O>(o).template call<ARGS...>(args...))
54 using Fwd =
typename FUNC::template fwd<O>;
55 using Idl_ret =
typename FUNC::result_type;
56 using Svr_ret =
decltype(Fwd(o).template call<ARGS...>(args...));
57 auto ret = Fwd(o).template call<ARGS...>(args...);
59 using L4::Types::numeric_limits;
62 if constexpr (numeric_limits<Svr_ret>::min() < numeric_limits<Idl_ret>::min())
64 if (
L4_UNLIKELY(ret < numeric_limits<Idl_ret>::min()))
71 if constexpr (numeric_limits<Svr_ret>::max() > numeric_limits<Idl_ret>::max())
73 l4_assert(ret <= numeric_limits<Idl_ret>::max());
74 if (
L4_UNLIKELY(ret > numeric_limits<Idl_ret>::max()))
79 if constexpr (numeric_limits<Svr_ret>::min() < numeric_limits<l4_msgtag_t>::min())
81 if (
L4_UNLIKELY(ret < numeric_limits<l4_msgtag_t>::min()))
84 if constexpr (numeric_limits<Svr_ret>::max() > numeric_limits<l4_msgtag_t>::max())
86 l4_assert(ret <= numeric_limits<l4_msgtag_t>::max());
87 if (
L4_UNLIKELY(ret > numeric_limits<l4_msgtag_t>::max()))
98template<
typename T,
typename SVR_TYPE,
typename ...M>
99struct Svr_arg : Svr_xmit<T>, Arg_pack<M...>
101 using Base = Arg_pack<M...>;
103 using svr_type = SVR_TYPE;
105 using xmit = Svr_xmit<T>;
111 template<Phase PHASE>
112 int get(
char *msg,
unsigned offset,
unsigned limit)
115 if constexpr(Is_input)
117 static_assert(PHASE == Phase::Data || PHASE ==
Phase::Items);
118 if constexpr (PHASE == Phase::Data)
125 return Base::template get<PHASE>(msg, r, limit);
130 return Base::template get<PHASE>(msg, offset, limit);
136 int reserve_data(
char *msg,
unsigned offset,
unsigned limit)
139 if constexpr (Is_output)
143 return Base::reserve_data(msg, r, limit);
148 template<Phase PHASE>
149 int set(
char *msg,
unsigned offset,
unsigned limit)
152 if constexpr (Is_output)
154 static_assert(PHASE == Phase::Data || PHASE ==
Phase::Items);
155 if constexpr (PHASE == Phase::Data)
164 return Base::template set<PHASE>(msg, r, limit);
167 template<
typename F,
typename ...ARGS>
168 decltype(
auto) call(F f, ARGS ...args)
171 return Base::template
172 call<F, ARGS..., svr_arg_type>(f, args..., this->v);
175 template<
typename ...ARGS>
176 void reply(ARGS &&...args)
179 if constexpr (Is_output)
180 reply_consume_arg<ARGS...>(L4::Types::forward<ARGS>(args)...);
182 Base::template reply<ARGS...>(L4::Types::forward<ARGS>(args)...);
185 template<
typename O,
typename FUNC,
typename ...ARGS>
186 decltype(
auto) obj_call(O *o, ARGS ...args)
189 return Base::template
190 obj_call<O, FUNC, ARGS..., svr_arg_type>(o, args..., this->v);
194 template<
typename A,
typename ...ARGS>
195 void reply_consume_arg(A &&a, ARGS &&...args)
197 this->v = L4::Types::move(a);
198 Base::template reply<ARGS...>(L4::Types::forward<ARGS>(args)...);
207template<
typename T,
typename ...M>
208struct Svr_arg<T, void, M...> : Arg_pack<M...>
211template<
typename A,
typename ...M>
212struct Arg_pack<A, M...> : Svr_arg<A, typename _Elem<A>::svr_type, M...>
224template<
typename R,
typename ...ARGS>
225struct Svr_arg_pack<R (ARGS...)> : Detail::Arg_pack<ARGS...>
227 using Base = Detail::Arg_pack<ARGS...>;
229 template<Phase PHASE>
230 int get(
void *msg,
unsigned offset,
unsigned limit)
232 char *buf =
static_cast<char *
>(msg);
233 return Base::template get<PHASE>(buf, offset, limit);
236 int reserve_data(
void *msg,
unsigned offset,
unsigned limit)
238 char *buf =
static_cast<char *
>(msg);
239 return Base::reserve_data(buf, offset, limit);
242 template<Phase PHASE>
243 int set(
void *msg,
unsigned offset,
unsigned limit)
245 char *buf =
static_cast<char *
>(msg);
246 return Base::template set<PHASE>(buf, offset, limit);
253template<
typename IPC_TYPE,
typename O,
typename ...ARGS>
257 using Pack = Svr_arg_pack<typename IPC_TYPE::rpc::ipc_type>;
260 Do_reply = IPC_TYPE::rpc::flags_type::Is_call,
272 int in_pos = Detail::Sizeof<typename IPC_TYPE::opcode_type>::size;
276 in_pos = pack.template get<Phase::Data>(&mrs->
mr[0], in_pos, in_bytes);
285 in_pos = pack.template get<Phase::Items>(&mrs->
mr[tag.
words()], 0,
291 asm volatile (
"" :
"=m" (mrs->
mr));
294 auto ret = pack.template obj_call<O,
typename IPC_TYPE::rpc, ARGS...>(o, args...);
305 int bytes = pack.template set<Phase::Data>(mrs->
mr, 0,
Mr_bytes);
310 bytes = pack.template set<Phase::Items>(&mrs->
mr[words], 0,
320template<
typename RPC,
typename ...OUT_ARGS>
324 static_assert(RPC::flags_type::Is_call,
"RPC to reply to must be a call.");
343 pack.template reply<OUT_ARGS...>(L4::Types::forward<OUT_ARGS>(args)...);
346 int bytes = pack.template set<Phase::Data>(mrs->
mr, 0,
Mr_bytes);
351 bytes = pack.template set<Phase::Items>(&mrs->
mr[words], 0,
373template<
typename RPC,
typename ...OUT_ARGS>
375reply(L4::Reply_cap reply_cap,
l4_ret_t res, OUT_ARGS && ...args)
378 return reply_cap.
reply(
379 L4::Ipc::Msg::pack_svr_reply<RPC, OUT_ARGS...>(
380 u, res, L4::Types::forward<OUT_ARGS>(args)...),
386template<
typename RPCS,
typename OPCODE_TYPE>
389template<
typename CLASS>
390struct Dispatch_call<L4::Typeid::Raw_ipc<CLASS>, void>
392 template<
typename OBJ,
typename ...ARGS>
394 call(OBJ *o,
l4_utcb_t *utcb, l4_msgtag_t tag, ARGS ...a)
396 return o->op_dispatch(utcb, tag, a...);
400template<
typename RPCS>
401struct Dispatch_call<RPCS, void>
403 constexpr static unsigned rmask()
404 {
return RPCS::rpc::flags_type::Rights & 3UL; }
406 template<
typename OBJ,
typename ...ARGS>
408 call(OBJ *o,
l4_utcb_t *utcb, l4_msgtag_t tag,
unsigned rights, ARGS ...a)
410 if ((rights & rmask()) != rmask())
413 using Rights = L4::Typeid::Rights<typename RPCS::rpc::class_type>;
414 return handle_svr_obj_call<RPCS>(o, utcb, tag,
415 Rights(rights), a...);
420template<
typename RPCS,
typename OPCODE_TYPE>
423 constexpr static unsigned rmask()
424 {
return RPCS::rpc::flags_type::Rights & 3UL; }
426 template<
typename OBJ,
typename ...ARGS>
428 _call(OBJ *o,
l4_utcb_t *utcb, l4_msgtag_t tag,
unsigned rights, OPCODE_TYPE op, ARGS ...a)
430 if (L4::Types::Same_v<typename RPCS::opcode_type, void>
431 || RPCS::Opcode == op)
433 if ((rights & rmask()) != rmask())
436 using Rights = L4::Typeid::Rights<typename RPCS::rpc::class_type>;
437 return handle_svr_obj_call<RPCS>(o, utcb, tag,
438 Rights(rights), a...);
440 return Dispatch_call<typename RPCS::next, OPCODE_TYPE>::template
441 _call<OBJ, ARGS...>(o, utcb, tag, rights, op, a...);
444 template<
typename OBJ,
typename ...ARGS>
446 call(OBJ *o,
l4_utcb_t *utcb, l4_msgtag_t tag,
unsigned rights, ARGS ...a)
450 using xmit = Svr_xmit<OPCODE_TYPE>;
451 auto *mrs =
reinterpret_cast<char *
>(l4_utcb_mr_u(utcb)->
mr);
452 l4_ret_t err = xmit::to_svr_data(mrs, 0, limit, op);
456 return _call<OBJ, ARGS...>(o, utcb, tag, rights, op, a...);
461struct Dispatch_call<Typeid::Detail::Rpcs_end, void>
463 template<
typename OBJ,
typename ...ARGS>
465 _call(OBJ *,
l4_utcb_t *, l4_msgtag_t,
unsigned,
int, ARGS ...)
468 template<
typename OBJ,
typename ...ARGS>
470 call(OBJ *,
l4_utcb_t *, l4_msgtag_t,
unsigned, ARGS ...)
474template<
typename OPCODE_TYPE>
475struct Dispatch_call<Typeid::Detail::Rpcs_end, OPCODE_TYPE> :
476 Dispatch_call<Typeid::Detail::Rpcs_end, void> {};
478template<
typename RPCS,
typename OBJ,
typename ...ARGS>
480dispatch_call(OBJ *o,
l4_utcb_t *utcb, l4_msgtag_t tag,
unsigned rights, ARGS ...a)
482 return Dispatch_call<typename RPCS::type, typename RPCS::opcode_type>::template
483 call<OBJ, ARGS...>(o, utcb, tag, rights, a...);
Type information handling.
l4_ret_t reply(l4_msgtag_t tag, l4_utcb_t *utcb=l4_utcb()) noexcept
Reply with this reply capability.
@ L4_EMSGTOOLONG
Message too long.
@ L4_EMSGERRRANGE
Error code range error.
@ L4_EMSGTOOSHORT
Message too short.
l4_msgtag_t l4_msgtag(long label, unsigned words, unsigned items, unsigned flags) L4_NOTHROW
Create a message tag from the specified values.
struct l4_utcb_t l4_utcb_t
Opaque type for the UTCB.
l4_utcb_t * l4_utcb(void) L4_NOTHROW L4_PURE
Get the UTCB address.
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.
#define L4_LIKELY(x)
Expression is likely to execute.
Interface Definition Language.
l4_int16_t l4_ret_t
Return value of an IPC call as well as an RPC call.
IPC Message related functionality.
@ Items
First phase: copy bytes to/from MRs.
@ Item_words
number of message words for one message item
@ Mr_bytes
number of bytes available in the UTCB message registers
@ Item_bytes
number of bytes for one message item
@ Word_bytes
number of bytes for one message word
@ Mr_words
number of message words available in the UTCB
IPC related functionality.
L4 low-level kernel interface.
static constexpr bool Is_output
Is the argument transferred from server to client?
static constexpr bool Is_optional
Is it an optional argument?
static constexpr bool Is_input
Is the argument transferred from client to server?
T svr_arg_type
The argument type for the server-side function.
Server-side RPC arguments data structure used to provide arguments to the server-side implementation ...
static constexpr int to_svr_items(char *msg, unsigned offset, unsigned limit, MTYPE &arg) noexcept
static constexpr int from_svr_items(char *msg, unsigned offset, unsigned limit, MTYPE const &arg) noexcept
static int to_svr_data(char *msg, unsigned offset, unsigned limit, MTYPE &arg) noexcept
Copy data from the message to a T server reference (arg must be MTYPE &).
static int from_svr_data(char *msg, unsigned offset, unsigned limit, MTYPE const &arg) noexcept
Copy a T into the message (arg must be either MTYPE or MTYPE const &).
static int reserve_data(char *, unsigned offs, unsigned limit, MTYPE &) noexcept
Prepare a T output operand (arg must be MTYPE &).
Message tag data structure.
unsigned words() const L4_NOTHROW
Get the number of untyped words.
unsigned items() const L4_NOTHROW
Get the number of typed items.
Low-level assert implementation.
#define l4_assert(expr)
Low-level assert.
l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]
Message registers.