L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
ipc_varg
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 "types"
11#include "ipc_basics"
12
13namespace L4 { namespace Ipc L4_EXPORT {
14
15template< typename T, template <typename X> class B >
16struct Generic_va_type : B<T>
17{
18 enum { Id = B<T>::Id };
19 using ID = B<T>;
20 using Ret_value = T const &;
21 using Value = T;
22
23 static Ret_value value(void const *d)
24 { return *reinterpret_cast<Value const *>(d); }
25
26 static void const *addr_of(Value const &v) { return &v; }
27
28 static unsigned size(void const *) { return sizeof(T); }
29
30 static L4_varg_type unsigned_id()
31 {
32 return static_cast<L4_varg_type>(Id & ~L4_VARG_TYPE_SIGN);
33 }
34
35 static L4_varg_type signed_id()
36 {
37 return static_cast<L4_varg_type>(Id | L4_VARG_TYPE_SIGN);
38 }
39
40 static L4_varg_type id()
41 {
42 return static_cast<L4_varg_type>(Id);
43 }
44};
45
46template< typename T > struct Va_type_id;
47template<> struct Va_type_id<l4_umword_t> { enum { Id = L4_VARG_TYPE_UMWORD }; };
48template<> struct Va_type_id<l4_mword_t> { enum { Id = L4_VARG_TYPE_MWORD }; };
49template<> struct Va_type_id<l4_fpage_t> { enum { Id = L4_VARG_TYPE_FPAGE }; };
50template<> struct Va_type_id<void> { enum { Id = L4_VARG_TYPE_NIL }; };
51template<> struct Va_type_id<char const *> { enum { Id = L4_VARG_TYPE_STRING }; };
52
53template< typename T > struct Va_type;
54
55template<> struct Va_type<l4_umword_t> : Generic_va_type<l4_umword_t, Va_type_id> {};
56template<> struct Va_type<l4_mword_t> : Generic_va_type<l4_mword_t, Va_type_id> {};
57template<> struct Va_type<l4_fpage_t> : Generic_va_type<l4_fpage_t, Va_type_id> {};
58
59template<> struct Va_type<void>
60{
61 using Ret_value = void;
62 using Value = void;
63
64 static void const *addr_of(void) { return 0; }
65
66 static void value(void const *) {}
67 static L4_varg_type id() { return L4_VARG_TYPE_NIL; }
68 static unsigned size(void const *) { return 0; }
69};
70
71template<> struct Va_type<char const *>
72{
73 using Ret_value = char const *;
74 using Value = char const *;
75
76 static void const *addr_of(Value v) { return v; }
77
78 static L4_varg_type id() { return L4_VARG_TYPE_STRING; }
79 static unsigned size(void const *s)
80 {
81 char const *_s = reinterpret_cast<char const *>(s);
82 int l = 1;
83 while (*_s)
84 {
85 ++_s; ++l;
86 }
87 return l;
88 }
89
90 static Ret_value value(void const *d) { return static_cast<char const *>(d); }
91};
92
96class Varg
97{
98public:
101
102private:
103 enum { Direct_data = 0x8000 };
104 Tag _tag;
105 char const *_d;
106
107public:
109 L4_varg_type type() const { return static_cast<L4_varg_type>(_tag & 0xff); }
114 unsigned length() const { return _tag >> 16; }
116 Tag tag() const { return _tag & ~static_cast<Tag>(Direct_data); }
118 void tag(Tag tag)
119 {
120 // Direct_data bit is not part of the write format. Make sure it cannot be
121 // set by a remote sender. Otherwise we would mistakenly treat the _d
122 // pointer as direct data.
123 _tag = tag & ~static_cast<Tag>(Direct_data);
124 }
125
126 void data(char const *d) { _d = d; }
127
129 char const *data() const
130 {
131 if (_tag & Direct_data)
132 {
133 union T { char const *d; char v[sizeof(char const *)]; };
134 return reinterpret_cast<T const *>(&_d)->v;
135 }
136 return _d;
137 }
138
140#if __cplusplus >= 201103L
141 Varg() = default;
142#else
143 Varg() {}
144#endif
145
147 Varg(L4_varg_type t, void const *v, int len)
148 : _tag(t | (static_cast<l4_mword_t>(len) << 16)),
149 _d(static_cast<char const *>(v))
150 {}
151
152 static Varg nil() { return Varg(L4_VARG_TYPE_NIL, 0, 0); }
153
160 template< typename V >
161 typename Va_type<V>::Ret_value value() const
162 {
163 if (_tag & Direct_data)
164 {
165 union X { char const *d; V v; };
166 return reinterpret_cast<X const &>(_d).v;
167 }
168
169 return Va_type<V>::value(_d);
170 }
171
172
174 template< typename T >
175 bool is_of() const { return Va_type<T>::id() == type(); }
176
178 bool is_nil() const { return is_of<void>(); }
179
181 bool is_of_int() const
182 { return (type() & ~L4_VARG_TYPE_SIGN) == L4_VARG_TYPE_UMWORD; }
183
190 template< typename T >
191 bool get_value(typename Va_type<T>::Value *v) const
192 {
193 if (!is_of<T>())
194 return false;
195
196 *v = this->value<T>();
197 return true;
198 }
199
201 template< typename T >
202 void set_value(void const *d)
203 {
204 using Vt = Va_type<T>;
205 _tag = Vt::id() | (Vt::size(d) << 16);
206 _d = static_cast<char const *>(d);
207 }
208
210 template<typename T>
211 void set_direct_value(T val, L4::Types::Enable_if_t<sizeof(T) <= sizeof(char const *), bool> = true)
212 {
213 static_assert(sizeof(T) <= sizeof(char const *), "direct Varg value too big");
214 using Vt = Va_type<T>;
215 _tag = Vt::id() | (sizeof(T) << 16) | Direct_data;
216 union X { char const *d; T v; };
217 reinterpret_cast<X &>(_d).v = val;
218 }
219
221 template<typename T> explicit
222 Varg(T const *data) { set_value<T>(data); }
225
227 template<typename T> explicit
228 Varg(T data, L4::Types::Enable_if_t<sizeof(T) <= sizeof(char const *), bool> = true)
230};
231
232
233template<typename T>
234class Varg_t : public Varg
235{
236public:
237 using Value = typename Va_type<T>::Value;
238 explicit Varg_t(Value v) : Varg()
239 { _data = v; set_value<T>(Va_type<T>::addr_of(_data)); }
240
241private:
242 Value _data;
243};
244
245template<unsigned MAX = L4_UTCB_GENERIC_DATA_SIZE>
246class Varg_list;
247
260{
261private:
262 template<unsigned T>
263 friend class Varg_list;
264
266 class Iter_state
267 {
268 private:
269 using M = l4_umword_t;
270 using Mp = M const *;
271 Mp _c;
272 Mp _e;
273
275 Mp next_arg(Varg const &a) const
276 {
277 return _c + 1 + (Msg::align_to<M>(a.length()) / sizeof(M));
278 }
279
280 public:
282 Iter_state() : _c(nullptr), _e(nullptr) {}
283
285 Iter_state(Mp c, Mp e) : _c(c), _e(e)
286 {}
287
289 bool valid() const
290 { return _c && _c < _e; }
291
293 Mp begin() const { return _c; }
294
296 Mp end() const { return _e; }
297
302 Varg pop()
303 {
304 if (!valid())
305 return Varg::nil();
306
307 Varg a;
308 a.tag(_c[0]);
309 a.data(reinterpret_cast<char const *>(&_c[1]));
310 _c = next_arg(a);
311 if (_c > _e)
312 return Varg::nil();
313
314 return a;
315 }
316
318 bool operator == (Iter_state const &o) const
319 { return _c == o._c; }
320
322 bool operator != (Iter_state const &o) const
323 { return _c != o._c; }
324 };
325
326 Iter_state _s;
327
328public:
330 Varg_list_ref() = default;
331
338 Varg_list_ref(void const *start, void const *end)
339 : _s(reinterpret_cast<l4_umword_t const *>(start),
340 reinterpret_cast<l4_umword_t const *>(end))
341 {}
342
345 {
346 private:
347 Iter_state _s;
348 Varg _a;
349
350 public:
352 Iterator(Iter_state const &s)
353 : _s(s)
354 {
355 _a = _s.pop();
356 }
357
359 explicit operator bool () const
360 { return !_a.is_nil(); }
361
364 {
365 if (!_a.is_nil())
366 _a = _s.pop();
367
368 return *this;
369 }
370
373 { return _a; }
374
376 bool equals(Iterator const &o) const
377 {
378 if (_a.is_nil() && o._a.is_nil())
379 return true;
380
381 return _s == o._s;
382 }
383
384 bool operator == (Iterator const &o) const
385 { return equals(o); }
386
387 bool operator != (Iterator const &o) const
388 { return !equals(o); }
389 };
390
393 { return _s.pop(); }
394
397 L4_DEPRECATED("Use range for or pop_front.")
398 { return _s.pop(); }
399
402 { return Iterator(_s); }
403
405 Iterator end() const
406 { return Iterator(Iter_state()); }
407};
408
420template<unsigned MAX>
421class Varg_list : public Varg_list_ref
422{
423 l4_umword_t data[MAX];
424 Varg_list(Varg_list const &);
425
426public:
429 {
430 if (!r._s.valid())
431 return;
432
433 l4_umword_t const *rs = r._s.begin();
434 unsigned c = r._s.end() - rs;
435
436 // The list comes from a message, so its length is up to the sender.
437 if (c > MAX)
438 c = MAX;
439
440 for (unsigned i = 0; i < c; ++i)
441 data[i] = rs[i];
442
443 this->_s = Iter_state(data, data + c);
444 }
445};
446
447
448namespace Msg {
449template<> struct Elem<Varg const *>
450{
451 using arg_type = Varg const *;
452 using svr_type = Varg_list_ref;
453 using svr_arg_type = Varg_list_ref;
454 static constexpr bool Is_optional = false;
455 static constexpr bool Is_input = true;
456 static constexpr bool Is_output = false;
457};
458
459template<> struct Is_valid_rpc_type<Varg> : L4::Types::False {};
460template<> struct Is_valid_rpc_type<Varg *> : L4::Types::False {};
461template<> struct Is_valid_rpc_type<Varg &> : L4::Types::False {};
462template<> struct Is_valid_rpc_type<Varg const &> : L4::Types::False {};
463
464template<>
465struct Clnt_val_ops<Varg> :
466 Clnt_noops<Varg const &>
467{
468 static int to_msg_data(char *msg, unsigned offs, unsigned limit,
469 Varg const &a)
470 {
471 for (Varg const *i = &a; i->tag(); ++i)
472 {
473 offs = align_to<l4_umword_t>(offs);
474 if (L4_UNLIKELY(!check_size<l4_umword_t>(offs, limit)))
475 return -L4_EMSGTOOLONG;
476 *reinterpret_cast<l4_umword_t*>(msg + offs) = i->tag();
477 offs += sizeof(l4_umword_t);
478 if (L4_UNLIKELY(!check_size<char>(offs, limit, i->length())))
479 return -L4_EMSGTOOLONG;
480 char const *d = i->data();
481 for (unsigned x = 0; x < i->length(); ++x)
482 msg[offs++] = *d++;
483 }
484
485 return offs;
486 }
487};
488
489template<>
490struct Svr_val_ops<Varg_list_ref> :
491 Svr_noops<Varg_list_ref>
492{
493 static int to_svr_data(char *msg, unsigned offset, unsigned limit,
494 Varg_list_ref &a)
495 {
496 unsigned start = align_to<l4_umword_t>(offset);
497 unsigned offs;
498 for (offs = start; offs < limit;)
499 {
500 unsigned noffs = align_to<l4_umword_t>(offs);
501 if (L4_UNLIKELY(!check_size<l4_umword_t>(noffs, limit)))
502 break;
503
504 offs = noffs;
505 Varg arg;
506 arg.tag(*reinterpret_cast<l4_umword_t*>(msg + offs));
507
508 if (!arg.tag())
509 break;
510
511 offs += sizeof(l4_umword_t);
512
513 if (L4_UNLIKELY(!check_size<char>(offs, limit, arg.length())))
514 return -L4_EMSGTOOLONG;
515 offs += arg.length();
516 }
517
518 a = Varg_list_ref(msg + start, msg + align_to<l4_umword_t>(offs));
519 return offs;
520 }
521};
522}
523}}
Iterator for Valists.
Definition ipc_varg:345
Iterator(Iter_state const &s)
Create a new iterator.
Definition ipc_varg:352
bool equals(Iterator const &o) const
check for equality
Definition ipc_varg:376
Iterator & operator++()
increment iterator to the next arg
Definition ipc_varg:363
Varg operator*() const
dereference the iterator, get Varg
Definition ipc_varg:372
Iterator begin() const
Returns an iterator to the first Varg.
Definition ipc_varg:401
Varg pop_front()
Get the next parameter in the list.
Definition ipc_varg:392
Varg next()
Get the next parameter in the list.
Definition ipc_varg:396
Varg_list_ref(void const *start, void const *end)
Create a parameter list over a given memory region.
Definition ipc_varg:338
Iterator end() const
Returns the end of the list.
Definition ipc_varg:405
Varg_list_ref()=default
Create an empty parameter list.
Self-contained list of variable-sized RPC parameters.
Definition ipc_varg:422
Varg_list(Varg_list_ref const &r)
Create a parameter list as a copy from a referencing list.
Definition ipc_varg:428
Variably sized RPC argument.
Definition ipc_varg:97
bool is_of_int() const
Definition ipc_varg:181
Varg(char const *data)
Make Varg from null-terminated string.
Definition ipc_varg:224
char const * data() const
Definition ipc_varg:129
Varg(L4_varg_type t, void const *v, int len)
Make an indirect varg.
Definition ipc_varg:147
Varg()=default
Make uninitialized Varg.
void set_direct_value(T val, L4::Types::Enable_if_t< sizeof(T)<=sizeof(char const *), bool >=true)
Set to directly stored value of type T.
Definition ipc_varg:211
Va_type< V >::Ret_value value() const
Definition ipc_varg:161
bool is_of() const
Definition ipc_varg:175
unsigned length() const
Get the size of the RPC argument.
Definition ipc_varg:114
void set_value(void const *d)
Set to indirect value of type T.
Definition ipc_varg:202
Tag tag() const
Definition ipc_varg:116
L4_varg_type type() const
Definition ipc_varg:109
void tag(Tag tag)
Set Varg tag (usually from message).
Definition ipc_varg:118
Varg(T const *data)
Make Varg from indirect value (pointer).
Definition ipc_varg:222
Varg(T data, L4::Types::Enable_if_t< sizeof(T)<=sizeof(char const *), bool >=true)
Make Varg from direct value.
Definition ipc_varg:228
l4_umword_t Tag
The data type for the tag.
Definition ipc_varg:100
void data(char const *d)
Set Varg to indirect data value (usually in UTCB).
Definition ipc_varg:126
bool is_nil() const
Definition ipc_varg:178
bool get_value(typename Va_type< T >::Value *v) const
Get the value of the Varg as type T.
Definition ipc_varg:191
unsigned long l4_umword_t
Unsigned machine word.
Definition l4int.h:40
signed long l4_mword_t
Signed machine word.
Definition l4int.h:37
@ L4_EMSGTOOLONG
Message too long.
Definition err.h:59
#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_DEPRECATED(s)
Mark symbol deprecated.
Definition compiler.h:300
constexpr bool check_size(unsigned offset, unsigned limit) noexcept
Check if there is enough space for T from offset to limit.
Definition ipc_basics:50
constexpr unsigned long align_to(unsigned long bytes, unsigned long align) noexcept
Pad bytes to the given alignment align (in bytes).
Definition ipc_basics:27
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.
Empty client side marshalling code.
Definition ipc_basics:194
Defines client-side handling of 'MTYPE' as RPC argument.
Definition ipc_basics:409
static int to_msg_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 &).
Definition ipc_basics:414
Type trait defining a valid RPC parameter type.
Definition ipc_basics:521
Empty server side marshalling code.
Definition ipc_basics:295
Defines server-side handling of 'MTYPE' as RPC argument.
Definition ipc_basics:439
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 &).
Definition ipc_basics:444
False meta value.
Definition types:322