L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
ipc_server
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_iface>
12#include <l4/sys/cxx/limits>
13#include <l4/sys/__typeinfo.h>
14#include <l4/sys/assert.h>
15#include <l4/sys/err.h>
16#include <stddef.h>
17
18namespace L4 {
19namespace Ipc {
20namespace Msg {
21namespace Detail {
22
23template<typename T> struct Sizeof { enum { size = sizeof(T) }; };
24template<> struct Sizeof<void> { enum { size = 0 }; };
25
29template<typename ...> struct Arg_pack
30{
31 template<typename DIR>
32 unsigned get(char *, unsigned offset, unsigned)
33 { return offset; }
34
35 template<typename DIR>
36 unsigned set(char *, unsigned offset, unsigned, l4_ret_t)
37 { return offset; }
38
39 template<typename F, typename ...ARGS>
40 decltype(auto) call(F f, ARGS ...args)
41 { return f(args...); }
42
43 template<typename O, typename FUNC, typename ...ARGS>
44 auto obj_call(O *o, ARGS ...args)
45 -> decltype(typename FUNC::template fwd<O>(o).template call<ARGS...>(args...))
46 {
47 typedef typename FUNC::template fwd<O> Fwd;
48 using Idl_ret = typename FUNC::result_type;
49 using Svr_ret = decltype(Fwd(o).template call<ARGS...>(args...));
50 auto ret = Fwd(o).template call<ARGS...>(args...);
51
52 using L4::Types::numeric_limits;
53 // Truncating a negative return value which is too small could result in a
54 // positive value pretending "success" to the caller.
55 if constexpr (numeric_limits<Svr_ret>::min() < numeric_limits<Idl_ret>::min())
56 {
57 if (L4_UNLIKELY(ret < numeric_limits<Idl_ret>::min()))
58 return -L4_EMSGERRRANGE;
59 }
60 // Truncating a positive return value which is too large results either in a
61 // positive value different from the original return value (but interpreted
62 // as "success" by the caller) or in a negative value. Trigger an assertion
63 // in these cases but also return an error in case of NDEBUG=y.
64 if constexpr (numeric_limits<Svr_ret>::max() > numeric_limits<Idl_ret>::max())
65 {
66 l4_assert(ret <= numeric_limits<Idl_ret>::max());
67 if (L4_UNLIKELY(ret > numeric_limits<Idl_ret>::max()))
68 return -L4_EMSGERRRANGE;
69 }
70 // The following two checks are required in case the Idl_ret limits exceed
71 // the limits of the 'label' part of l4_msgtag_t.
72 if constexpr (numeric_limits<Svr_ret>::min() < numeric_limits<l4_msgtag_t>::min())
73 {
74 if (L4_UNLIKELY(ret < numeric_limits<l4_msgtag_t>::min()))
75 return -L4_EMSGERRRANGE;
76 }
77 if constexpr (numeric_limits<Svr_ret>::max() > numeric_limits<l4_msgtag_t>::max())
78 {
79 l4_assert(ret <= numeric_limits<l4_msgtag_t>::max());
80 if (L4_UNLIKELY(ret > numeric_limits<l4_msgtag_t>::max()))
81 return -L4_EMSGERRRANGE;
82 }
83
84 return ret;
85 }
86};
87
91template<typename T, typename SVR_TYPE, typename ...M>
92struct Svr_arg : Svr_xmit<T>, Arg_pack<M...>
93{
94 typedef Arg_pack<M...> Base;
95
96 typedef SVR_TYPE svr_type;
97 typedef typename _Elem<T>::svr_arg_type svr_arg_type;
98
99 svr_type v;
100
101 template<typename DIR>
102 int get(char *msg, unsigned offset, unsigned limit)
103 {
104 typedef Svr_xmit<T> ct;
105 int r = ct::to_svr(msg, offset, limit, this->v,
106 typename DIR::dir(), typename DIR::cls());
107 if (L4_LIKELY(r >= 0))
108 return Base::template get<DIR>(msg, r, limit);
109
110 if (_Elem<T>::Is_optional)
111 {
112 v = svr_type();
113 return Base::template get<DIR>(msg, offset, limit);
114 }
115 return r;
116 }
117
118 template<typename DIR>
119 int set(char *msg, unsigned offset, unsigned limit, l4_ret_t ret)
120 {
121 typedef Svr_xmit<T> ct;
122 int r = ct::from_svr(msg, offset, limit, ret, this->v,
123 typename DIR::dir(), typename DIR::cls());
124 if (L4_UNLIKELY(r < 0))
125 return r;
126 return Base::template set<DIR>(msg, r, limit, ret);
127 }
128
129 template<typename F, typename ...ARGS>
130 decltype(auto) call(F f, ARGS ...args)
131 {
132 //As_arg<value_type> check;
133 return Base::template
134 call<F, ARGS..., svr_arg_type>(f, args..., this->v);
135 }
136
137 template<typename O, typename FUNC, typename ...ARGS>
138 decltype(auto) obj_call(O *o, ARGS ...args)
139 {
140 //As_arg<value_type> check;
141 return Base::template
142 obj_call<O, FUNC, ARGS..., svr_arg_type>(o, args..., this->v);
143 }
144};
145
146template<typename T, typename ...M>
147struct Svr_arg<T, void, M...> : Arg_pack<M...>
148{
149 typedef Arg_pack<M...> Base;
150
151 template<typename DIR>
152 int get(char *msg, unsigned offset, unsigned limit)
153 { return Base::template get<DIR>(msg, offset, limit); }
154
155 template<typename DIR>
156 int set(char *msg, unsigned offset, unsigned limit, l4_ret_t ret)
157 { return Base::template set<DIR>(msg, offset, limit, ret); }
158
159 template<typename F, typename ...ARGS>
160 decltype(auto) call(F f, ARGS ...args)
161 {
162 return Base::template call<F, ARGS...>(f, args...);
163 }
164
165 template<typename O, typename FUNC, typename ...ARGS>
166 decltype(auto) obj_call(O *o, ARGS ...args)
167 {
168 return Base::template obj_call<O, FUNC, ARGS...>(o, args...);
169 }
170};
171
172template<typename A, typename ...M>
173struct Arg_pack<A, M...> : Svr_arg<A, typename _Elem<A>::svr_type, M...>
174{};
175
176} // namespace Detail
177
178//---------------------------------------------------------------------
183template<typename IPC_TYPE> struct Svr_arg_pack;
184
185template<typename R, typename ...ARGS>
186struct Svr_arg_pack<R (ARGS...)> : Detail::Arg_pack<ARGS...>
187{
188 typedef Detail::Arg_pack<ARGS...> Base;
189 template<typename DIR>
190 int get(void *msg, unsigned offset, unsigned limit)
191 {
192 char *buf = static_cast<char *>(msg);
193 return Base::template get<DIR>(buf, offset, limit);
194 }
195
196 template<typename DIR>
197 int set(void *msg, unsigned offset, unsigned limit, l4_ret_t ret)
198 {
199 char *buf = static_cast<char *>(msg);
200 return Base::template set<DIR>(buf, offset, limit, ret);
201 }
202};
203
207template<typename IPC_TYPE, typename O, typename ...ARGS>
208static l4_msgtag_t
209handle_svr_obj_call(O *o, l4_utcb_t *utcb, l4_msgtag_t tag, ARGS ...args)
210{
211 typedef Svr_arg_pack<typename IPC_TYPE::rpc::ipc_type> Pack;
212 enum
213 {
214 Do_reply = IPC_TYPE::rpc::flags_type::Is_call,
215 Short_err = Do_reply ? -L4_EMSGTOOSHORT : -L4_ENOREPLY,
216 };
217
218 // XXX: send a reply or just do not reply in case of a cheating client
219 if (L4_UNLIKELY(tag.words() + tag.items() * Item_words > Mr_words))
220 return l4_msgtag(Short_err, 0, 0, 0);
221
222 // our whole arguments data structure
223 Pack pack;
224 l4_msg_regs_t *mrs = l4_utcb_mr_u(utcb);
225
226 int in_pos = Detail::Sizeof<typename IPC_TYPE::opcode_type>::size;
227
228 unsigned const in_bytes = tag.words() * Word_bytes;
229
230 in_pos = pack.template get<Do_in_data>(&mrs->mr[0], in_pos, in_bytes);
231
232 if (L4_UNLIKELY(in_pos < 0))
233 return l4_msgtag(Short_err, 0, 0, 0);
234
235 if (L4_UNLIKELY(pack.template get<Do_out_data>(mrs->mr, 0, Mr_bytes) < 0))
236 return l4_msgtag(Short_err, 0, 0, 0);
237
238
239 in_pos = pack.template get<Do_in_items>(&mrs->mr[tag.words()], 0,
240 tag.items() * Item_bytes);
241
242 if (L4_UNLIKELY(in_pos < 0))
243 return l4_msgtag(Short_err, 0, 0, 0);
244
245 asm volatile ("" : "=m" (mrs->mr));
246
247 // call the server function
248 auto ret = pack.template obj_call<O, typename IPC_TYPE::rpc, ARGS...>(o, args...);
249
250 if (!Do_reply)
251 return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
252
253 // our convention says that negative return value means no
254 // reply data
255 if (L4_UNLIKELY(ret < 0))
256 return l4_msgtag(ret, 0, 0, 0);
257
258 // reply with the reply data from the server function
259 int bytes = pack.template set<Do_out_data>(mrs->mr, 0, Mr_bytes, ret);
260 if (L4_UNLIKELY(bytes < 0))
261 return l4_msgtag(-L4_EMSGTOOLONG, 0, 0, 0);
262
263 unsigned words = (bytes + Word_bytes - 1) / Word_bytes;
264 bytes = pack.template set<Do_out_items>(&mrs->mr[words], 0,
265 Mr_bytes - words * Word_bytes,
266 ret);
267 if (L4_UNLIKELY(bytes < 0))
268 return l4_msgtag(-L4_EMSGTOOLONG, 0, 0, 0);
269
270 unsigned const items = bytes / Item_bytes;
271 return l4_msgtag(ret, words, items, 0);
272}
273
274//-------------------------------------------------------------------------
275
276template<typename RPCS, typename OPCODE_TYPE>
277struct Dispatch_call;
278
279template<typename CLASS>
280struct Dispatch_call<L4::Typeid::Raw_ipc<CLASS>, void>
281{
282 template<typename OBJ, typename ...ARGS>
283 static l4_msgtag_t
284 call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, ARGS ...a)
285 {
286 return o->op_dispatch(utcb, tag, a...);
287 }
288};
289
290template<typename RPCS>
291struct Dispatch_call<RPCS, void>
292{
293 constexpr static unsigned rmask()
294 { return RPCS::rpc::flags_type::Rights & 3UL; }
295
296 template<typename OBJ, typename ...ARGS>
297 static l4_msgtag_t
298 call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, ARGS ...a)
299 {
300 if ((rights & rmask()) != rmask())
301 return l4_msgtag(-L4_EPERM, 0, 0, 0);
302
303 typedef L4::Typeid::Rights<typename RPCS::rpc::class_type> Rights;
304 return handle_svr_obj_call<RPCS>(o, utcb, tag,
305 Rights(rights), a...);
306
307 }
308};
309
310template<typename RPCS, typename OPCODE_TYPE>
311struct Dispatch_call
312{
313 constexpr static unsigned rmask()
314 { return RPCS::rpc::flags_type::Rights & 3UL; }
315
316 template<typename OBJ, typename ...ARGS>
317 static l4_msgtag_t
318 _call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, OPCODE_TYPE op, ARGS ...a)
319 {
320 if (L4::Types::Same<typename RPCS::opcode_type, void>::value
321 || RPCS::Opcode == op)
322 {
323 if ((rights & rmask()) != rmask())
324 return l4_msgtag(-L4_EPERM, 0, 0, 0);
325
326 typedef L4::Typeid::Rights<typename RPCS::rpc::class_type> Rights;
327 return handle_svr_obj_call<RPCS>(o, utcb, tag,
328 Rights(rights), a...);
329 }
330 return Dispatch_call<typename RPCS::next, OPCODE_TYPE>::template
331 _call<OBJ, ARGS...>(o, utcb, tag, rights, op, a...);
332 }
333
334 template<typename OBJ, typename ...ARGS>
335 static l4_msgtag_t
336 call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, ARGS ...a)
337 {
338 OPCODE_TYPE op;
339 unsigned limit = tag.words() * Word_bytes;
340 typedef Svr_xmit<OPCODE_TYPE> S;
341 l4_ret_t err = S::to_svr(reinterpret_cast<char *>(l4_utcb_mr_u(utcb)->mr), 0,
342 limit, op, Dir_in(), Cls_data());
343 if (L4_UNLIKELY(err < 0))
344 return l4_msgtag(-L4_EMSGTOOSHORT, 0, 0, 0);
345
346 return _call<OBJ, ARGS...>(o, utcb, tag, rights, op, a...);
347 }
348};
349
350template<>
351struct Dispatch_call<Typeid::Detail::Rpcs_end, void>
352{
353 template<typename OBJ, typename ...ARGS>
354 static l4_msgtag_t
355 _call(OBJ *, l4_utcb_t *, l4_msgtag_t, unsigned, int, ARGS ...)
356 { return l4_msgtag(-L4_ENOSYS, 0, 0, 0); }
357
358 template<typename OBJ, typename ...ARGS>
359 static l4_msgtag_t
360 call(OBJ *, l4_utcb_t *, l4_msgtag_t, unsigned, ARGS ...)
361 { return l4_msgtag(-L4_ENOSYS, 0, 0, 0); }
362};
363
364template<typename OPCODE_TYPE>
365struct Dispatch_call<Typeid::Detail::Rpcs_end, OPCODE_TYPE> :
366 Dispatch_call<Typeid::Detail::Rpcs_end, void> {};
367
368template<typename RPCS, typename OBJ, typename ...ARGS>
369static l4_msgtag_t
370dispatch_call(OBJ *o, l4_utcb_t *utcb, l4_msgtag_t tag, unsigned rights, ARGS ...a)
371{
372 return Dispatch_call<typename RPCS::type, typename RPCS::opcode_type>::template
373 call<OBJ, ARGS...>(o, utcb, tag, rights, a...);
374}
375
376} // namespace Msg
377} // namesapce Ipc
378} // namespace L4
Type information handling.
Error codes.
@ L4_ENOSYS
No sys.
Definition err.h:51
@ L4_ENOREPLY
No reply.
Definition err.h:56
@ L4_EMSGTOOLONG
Message too long.
Definition err.h:58
@ L4_EMSGERRRANGE
Error code range error.
Definition err.h:60
@ L4_EPERM
No permission.
Definition err.h:34
@ L4_EMSGTOOSHORT
Message too short.
Definition err.h:57
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
struct l4_utcb_t l4_utcb_t
Opaque type for the UTCB.
Definition utcb.h:56
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:289
#define L4_LIKELY(x)
Expression is likely to execute.
Definition compiler.h:288
Interface Definition Language.
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_words
number of message words for one message item
Definition ipc_basics:90
@ Mr_bytes
number of bytes available in the UTCB message registers
Definition ipc_basics:96
@ 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
@ Mr_words
number of message words available in the UTCB
Definition ipc_basics:94
IPC related functionality.
Definition ipc_array:13
L4 low-level kernel interface.
Server-side RPC arguments data structure used to provide arguments to the server-side implementation ...
Definition ipc_server:183
Message tag data structure.
Definition types.h:266
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
Low-level assert implementation.
#define l4_assert(expr)
Low-level assert.
Definition assert.h:32
Encapsulation of the message-register block in the UTCB.
Definition utcb.h:133
l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]
Message registers.
Definition utcb.h:134