L4Re – L4 Runtime Environment
ipc_varg
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /*
3  * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  *
9  * As a special exception, you may use this file as part of a free software
10  * library without restriction. Specifically, if other files instantiate
11  * templates or use macros or inline functions from this file, or you compile
12  * this file and link it with other files to produce an executable, this
13  * file does not by itself cause the resulting executable to be covered by
14  * the GNU General Public License. This exception does not however
15  * invalidate any other reasons why the executable file might be covered by
16  * the GNU General Public License.
17  */
18 #pragma once
19 #pragma GCC system_header
20 
21 #include "types"
22 #include "ipc_basics"
23 
24 namespace L4 { namespace Ipc L4_EXPORT {
25 
26 template< typename T, template <typename X> class B >
27 struct Generic_va_type : B<T>
28 {
29  enum { Id = B<T>::Id };
30  typedef B<T> ID;
31  typedef T const &Ret_value;
32  typedef T Value;
33 
34  static Ret_value value(void const *d)
35  { return *reinterpret_cast<Value const *>(d); }
36 
37  static void const *addr_of(Value const &v) { return &v; }
38 
39  static unsigned size(void const *) { return sizeof(T); }
40 
41  static L4_varg_type unsigned_id() { return (L4_varg_type)(Id & ~L4_VARG_TYPE_SIGN); }
42  static L4_varg_type signed_id() { return (L4_varg_type)(Id | L4_VARG_TYPE_SIGN); }
43  static L4_varg_type id() { return (L4_varg_type)Id; }
44 };
45 
46 template< typename T > struct Va_type_id;
47 template<> struct Va_type_id<l4_umword_t> { enum { Id = L4_VARG_TYPE_UMWORD }; };
48 template<> struct Va_type_id<l4_mword_t> { enum { Id = L4_VARG_TYPE_MWORD }; };
49 template<> struct Va_type_id<l4_fpage_t> { enum { Id = L4_VARG_TYPE_FPAGE }; };
50 template<> struct Va_type_id<void> { enum { Id = L4_VARG_TYPE_NIL }; };
51 template<> struct Va_type_id<char const *> { enum { Id = L4_VARG_TYPE_STRING }; };
52 
53 template< typename T > struct Va_type;
54 
55 template<> struct Va_type<l4_umword_t> : Generic_va_type<l4_umword_t, Va_type_id> {};
56 template<> struct Va_type<l4_mword_t> : Generic_va_type<l4_mword_t, Va_type_id> {};
57 template<> struct Va_type<l4_fpage_t> : Generic_va_type<l4_fpage_t, Va_type_id> {};
58 
59 template<> struct Va_type<void>
60 {
61  typedef void Ret_value;
62  typedef void Value;
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 
71 template<> struct Va_type<char const *>
72 {
73  typedef char const *Ret_value;
74  typedef char const *Value;
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 (char const *)d; }
91 };
92 
96 class Varg
97 {
98 private:
99  enum { Direct_data = 0x8000 };
100  l4_umword_t _tag;
101  char const *_d;
102 
103 public:
104 
106  typedef l4_umword_t Tag;
107 
109  L4_varg_type type() const { return (L4_varg_type)(_tag & 0xff); }
114  unsigned length() const { return _tag >> 16; }
116  Tag tag() const { return _tag & ~Direct_data; }
118  void tag(Tag tag) { _tag = tag; }
120  void data(char const *d) { _d = d; }
121 
123  char const *data() const
124  {
125  if (_tag & Direct_data)
126  {
127  union T { char const *d; char v[sizeof(char const *)]; };
128  return reinterpret_cast<T const *>(&_d)->v;
129  }
130  return _d;
131  }
132 
134 #if __cplusplus >= 201103L
135  Varg() = default;
136 #else
137  Varg() {}
138 #endif
139 
141  Varg(L4_varg_type t, void const *v, int len)
142  : _tag(t | ((l4_mword_t)len << 16)), _d((char const *)v)
143  {}
144 
145  static Varg nil() { return Varg(L4_VARG_TYPE_NIL, 0, 0); }
146 
153  template< typename V >
154  typename Va_type<V>::Ret_value value() const
155  {
156  if (_tag & Direct_data)
157  {
158  union X { char const *d; V v; };
159  return reinterpret_cast<X const &>(_d).v;
160  }
161 
162  return Va_type<V>::value(_d);
163  }
164 
165 
167  template< typename T >
168  bool is_of() const { return Va_type<T>::id() == type(); }
169 
171  bool is_nil() const { return is_of<void>(); }
172 
174  bool is_of_int() const
175  { return (type() & ~L4_VARG_TYPE_SIGN) == L4_VARG_TYPE_UMWORD; }
176 
183  template< typename T >
184  bool get_value(typename Va_type<T>::Value *v) const
185  {
186  if (!is_of<T>())
187  return false;
188 
189  *v = this->value<T>();
190  return true;
191  }
192 
194  template< typename T >
195  void set_value(void const *d)
196  {
197  typedef Va_type<T> Vt;
198  _tag = Vt::id() | (Vt::size(d) << 16);
199  _d = (char const *)d;
200  }
201 
203  template<typename T>
204  void set_direct_value(T val, typename L4::Types::Enable_if<sizeof(T) <= sizeof(char const *), bool>::type = true)
205  {
206  static_assert(sizeof(T) <= sizeof(char const *), "direct Varg value too big");
207  typedef Va_type<T> Vt;
208  _tag = Vt::id() | (sizeof(T) << 16) | Direct_data;
209  union X { char const *d; T v; };
210  reinterpret_cast<X &>(_d).v = val;
211  }
212 
214  template<typename T> explicit
215  Varg(T const *data) { set_value<T>(data); }
217  Varg(char const *data) { set_value<char const *>(data); }
218 
220  template<typename T> explicit
221  Varg(T data, typename L4::Types::Enable_if<sizeof(T) <= sizeof(char const *), bool>::type = true)
222  { set_direct_value<T>(data); }
223 };
224 
225 
226 template<typename T>
227 class Varg_t : public Varg
228 {
229 public:
230  typedef typename Va_type<T>::Value Value;
231  explicit Varg_t(Value v) : Varg()
232  { _data = v; set_value<T>(Va_type<T>::addr_of(_data)); }
233 
234 private:
235  Value _data;
236 };
237 
238 template<unsigned MAX = L4_UTCB_GENERIC_DATA_SIZE>
239 class Varg_list;
240 
253 {
254 private:
255  template<unsigned T>
256  friend class Varg_list;
257 
259  class Iter_state
260  {
261  private:
262  using M = l4_umword_t;
263  using Mp = M const *;
264  Mp _c;
265  Mp _e;
266 
268  Mp next_arg(Varg const &a) const
269  {
270  return _c + 1 + (Msg::align_to<M>(a.length()) / sizeof(M));
271  }
272 
273  public:
275  Iter_state() : _c(nullptr) {}
276 
278  Iter_state(Mp c, Mp e) : _c(c), _e(e)
279  {}
280 
282  bool valid() const
283  { return _c && _c < _e; }
284 
286  Mp begin() const { return _c; }
287 
289  Mp end() const { return _e; }
290 
295  Varg pop()
296  {
297  if (!valid())
298  return Varg::nil();
299 
300  Varg a;
301  a.tag(_c[0]);
302  a.data(reinterpret_cast<char const *>(&_c[1]));
303  _c = next_arg(a);
304  if (_c > _e)
305  return Varg::nil();
306 
307  return a;
308  }
309 
311  bool operator == (Iter_state const &o) const
312  { return _c == o._c; }
313 
315  bool operator != (Iter_state const &o) const
316  { return _c != o._c; }
317  };
318 
319  Iter_state _s;
320 
321 public:
323  Varg_list_ref() = default;
324 
331  Varg_list_ref(void const *start, void const *end)
332  : _s(reinterpret_cast<l4_umword_t const *>(start),
333  reinterpret_cast<l4_umword_t const *>(end))
334  {}
335 
337  class Iterator
338  {
339  private:
340  Iter_state _s;
341  Varg _a;
342 
343  public:
345  Iterator(Iter_state const &s)
346  : _s(s)
347  {
348  _a = _s.pop();
349  }
350 
352  explicit operator bool () const
353  { return !_a.is_nil(); }
354 
357  {
358  if (!_a.is_nil())
359  _a = _s.pop();
360 
361  return *this;
362  }
363 
366  { return _a; }
367 
369  bool equals(Iterator const &o) const
370  {
371  if (_a.is_nil() && o._a.is_nil())
372  return true;
373 
374  return _s == o._s;
375  }
376 
377  bool operator == (Iterator const &o) const
378  { return equals(o); }
379 
380  bool operator != (Iterator const &o) const
381  { return !equals(o); }
382  };
383 
386  { return _s.pop(); }
387 
390  L4_DEPRECATED("Use range for or pop_front.")
391  { return _s.pop(); }
392 
394  Iterator begin() const
395  { return Iterator(_s); }
396 
398  Iterator end() const
399  { return Iterator(Iter_state()); }
400 };
401 
409 template<unsigned MAX>
410 class Varg_list : public Varg_list_ref
411 {
412  l4_umword_t data[MAX];
413  Varg_list(Varg_list const &);
414 
415 public:
418  {
419  if (!r._s.valid())
420  return;
421 
422  l4_umword_t const *rs = r._s.begin();
423  unsigned c = r._s.end() - rs;
424  for (unsigned i = 0; i < c; ++i)
425  data[i] = rs[i];
426 
427  this->_s = Iter_state(data, data + c);
428  }
429 };
430 
431 
432 namespace Msg {
433 template<> struct Elem<Varg const *>
434 {
435  typedef Varg const *arg_type;
436  typedef Varg_list_ref svr_type;
437  typedef Varg_list_ref svr_arg_type;
438  enum { Is_optional = false };
439 };
440 
441 template<> struct Is_valid_rpc_type<Varg> : L4::Types::False {};
442 template<> struct Is_valid_rpc_type<Varg *> : L4::Types::False {};
443 template<> struct Is_valid_rpc_type<Varg &> : L4::Types::False {};
444 template<> struct Is_valid_rpc_type<Varg const &> : L4::Types::False {};
445 
446 template<> struct Direction<Varg const *> : Dir_in {};
447 template<> struct Class<Varg const *> : Cls_data {};
448 
449 template<typename DIR, typename CLASS>
450 struct Clnt_val_ops<Varg, DIR, CLASS>;
451 
452 template<>
453 struct Clnt_val_ops<Varg, Dir_in, Cls_data> :
454  Clnt_noops<Varg const &>
455 {
456  using Clnt_noops<Varg const &>::to_msg;
457  static int to_msg(char *msg, unsigned offs, unsigned limit,
458  Varg const &a, Dir_in, Cls_data)
459  {
460  for (Varg const *i = &a; i->tag(); ++i)
461  {
462  offs = align_to<l4_umword_t>(offs);
463  if (L4_UNLIKELY(!check_size<l4_umword_t>(offs, limit)))
464  return -L4_EMSGTOOLONG;
465  *reinterpret_cast<l4_umword_t*>(msg + offs) = i->tag();
466  offs += sizeof(l4_umword_t);
467  if (L4_UNLIKELY(!check_size<char>(offs, limit, i->length())))
468  return -L4_EMSGTOOLONG;
469  char const *d = i->data();
470  for (unsigned x = 0; x < i->length(); ++x)
471  msg[offs++] = *d++;
472  }
473 
474  return offs;
475  }
476 };
477 
478 template<>
479 struct Svr_val_ops<Varg_list_ref, Dir_in, Cls_data> :
480  Svr_noops<Varg_list_ref>
481 {
482  using Svr_noops<Varg_list_ref>::to_svr;
483  static int to_svr(char *msg, unsigned offset, unsigned limit,
484  Varg_list_ref &a, Dir_in, Cls_data)
485  {
486  unsigned start = align_to<l4_umword_t>(offset);
487  unsigned offs;
488  for (offs = start; offs < limit;)
489  {
490  unsigned noffs = align_to<l4_umword_t>(offs);
491  if (L4_UNLIKELY(!check_size<l4_umword_t>(noffs, limit)))
492  break;
493 
494  offs = noffs;
495  Varg arg;
496  arg.tag(*reinterpret_cast<l4_umword_t*>(msg + offs));
497 
498  if (!arg.tag())
499  break;
500 
501  offs += sizeof(l4_umword_t);
502 
503  if (L4_UNLIKELY(!check_size<char>(offs, limit, arg.length())))
504  return -L4_EMSGTOOLONG;
505  offs += arg.length();
506  }
507 
508  a = Varg_list_ref(msg + start, msg + align_to<l4_umword_t>(offs));
509  return offs;
510  }
511 };
512 }
513 }}
Iterator for Valists.
Definition: ipc_varg:338
Iterator(Iter_state const &s)
Create a new iterator.
Definition: ipc_varg:345
bool equals(Iterator const &o) const
check for equality
Definition: ipc_varg:369
Iterator & operator++()
increment iterator to the next arg
Definition: ipc_varg:356
Varg operator*() const
dereference the iterator, get Varg
Definition: ipc_varg:365
List of variable-sized RPC parameters as received by the server.
Definition: ipc_varg:253
Iterator begin() const
Returns an interator to the first Varg.
Definition: ipc_varg:394
Varg pop_front()
Get the next parameter in the list.
Definition: ipc_varg:385
Varg next()
Get the next parameter in the list.
Definition: ipc_varg:389
Varg_list_ref(void const *start, void const *end)
Create a parameter list over a given memory region.
Definition: ipc_varg:331
Iterator end() const
Returns the end of the list.
Definition: ipc_varg:398
Varg_list_ref()=default
Create an empty parameter list.
Self-contained list of variable-sized RPC parameters.
Definition: ipc_varg:411
Varg_list(Varg_list_ref const &r)
Create a parameter list as a copy from a referencing list.
Definition: ipc_varg:417
Variably sized RPC argument.
Definition: ipc_varg:97
bool is_of_int() const
Definition: ipc_varg:174
Varg(char const *data)
Make Varg from null-terminated string.
Definition: ipc_varg:217
Varg(L4_varg_type t, void const *v, int len)
Make an indirect varg.
Definition: ipc_varg:141
Varg()=default
Make uninitialized Varg.
l4_umword_t Tag
The data type for the tag.
Definition: ipc_varg:106
Va_type< V >::Ret_value value() const
Definition: ipc_varg:154
bool is_of() const
Definition: ipc_varg:168
void set_direct_value(T val, typename L4::Types::Enable_if< sizeof(T)<=sizeof(char const *), bool >::type=true)
Set to directly stored value of type T.
Definition: ipc_varg:204
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:195
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:215
Varg(T data, typename L4::Types::Enable_if< sizeof(T)<=sizeof(char const *), bool >::type=true)
Make Varg from direct value.
Definition: ipc_varg:221
void data(char const *d)
Set Varg to indirect data value (usually in UTCB)
Definition: ipc_varg:120
char const * data() const
Definition: ipc_varg:123
bool is_nil() const
Definition: ipc_varg:171
bool get_value(typename Va_type< T >::Value *v) const
Get the value of the Varg as type T.
Definition: ipc_varg:184
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition: compiler.h:238
#define L4_DEPRECATED(s)
Mark symbol deprecated.
Definition: compiler.h:243
unsigned long l4_umword_t
Unsigned machine word.
Definition: l4int.h:51
signed long l4_mword_t
Signed machine word.
Definition: l4int.h:48
@ L4_EMSGTOOLONG
Message too long.
Definition: err.h:67
L4 low-level kernel interface.
False meta value.
Definition: types:308
L4 flexpage type.
Definition: __l4_fpage.h:83