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 
93 /**
94  * Variably sized RPC argument.
95  */
96 class Varg
97 {
98 private:
99  enum { Direct_data = 0x8000 };
100  l4_umword_t _tag;
101  char const *_d;
102 
103 public:
104 
105  /// The data type for the tag
106  typedef l4_umword_t Tag;
107 
108  /// \return the type field of the tag
109  L4_varg_type type() const { return (L4_varg_type)(_tag & 0xff); }
110  /**
111  * Get the size of the RPC argument
112  * \return The size of the RPC argument
113  */
114  unsigned length() const { return _tag >> 16; }
115  /// \return the tag value (the Direct_data bit masked)
116  Tag tag() const { return _tag & ~Direct_data; }
117  /// Set Varg tag (usually from message)
118  void tag(Tag tag) { _tag = tag; }
119  /// Set Varg to indirect data value (usually in UTCB)
120  void data(char const *d) { _d = d; }
121 
122  /// \return pointer to the data, also safe for direct data
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 
133  /// Make uninitialized Varg
134 #if __cplusplus >= 201103L
135  Varg() = default;
136 #else
137  Varg() {}
138 #endif
139 
140  /// Make an indirect varg
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 
147  /**
148  * \tparam V The data type of the value to retrieve.
149  * \pre The Varg must be of type \a V (otherwise the result
150  * is unpredictable).
151  * \return The value of the Varg as type V.
152  */
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 
166  /// \return true if the Varg is of type T
167  template< typename T >
168  bool is_of() const { return Va_type<T>::id() == type(); }
169 
170  /// \return true if the Varg is of nil type.
171  bool is_nil() const { return is_of<void>(); }
172 
173  /// \return true if the Varg is an integer type (signed or unsigned).
174  bool is_of_int() const
175  { return (type() & ~L4_VARG_TYPE_SIGN) == L4_VARG_TYPE_UMWORD; }
176 
177  /**
178  * Get the value of the Varg as type T.
179  * \tparam T The expected type of the Varg.
180  * \param v Pointer to store the value
181  * \return true when the Varg is of type T, false if not
182  */
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 
193  /// Set to indirect value of type T
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 
202  /// Set to directly stored value of type T
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 
213  /// Make Varg from indirect value (pointer)
214  template<typename T> explicit
215  Varg(T const *data) { set_value<T>(data); }
216  /// Make Varg from null-terminated string
217  Varg(char const *data) { set_value<char const *>(data); }
218 
219  /// Make Varg from direct value
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 
241 /**
242  * List of variable-sized RPC parameters as received by the server.
243  *
244  * The list can be traversed exactly once using \a next().
245  *
246  * This is a reference list, where the returned Varg point to
247  * data in the underlying storage, conventionally the UTCB.
248  * This type should only be used in server functions when the
249  * implementation can ensure that all content is read before
250  * the UTCB is reused (e.g. for IPC), otherwise use Varg_list.
251  */
252 class Varg_list_ref
253 {
254 private:
255  template<unsigned T>
256  friend class Varg_list;
257  l4_umword_t const *_end;
258  l4_umword_t const *_current;
259 
260 public:
261  /// Create an empty parameter list.
262  Varg_list_ref() : _end(0), _current(0) {}
263  /**
264  * Create a parameter list over a given memory region.
265  *
266  * \param start Pointer to start of the parameter list.
267  * \param end Pointer to end of the list (inclusive).
268  */
269  Varg_list_ref(void const *start, void const *end)
270  : _end(reinterpret_cast<l4_umword_t const *>(end)),
271  _current(reinterpret_cast<l4_umword_t const *>(start))
272  {}
273 
274  /// Get the next parameter in the list.
275  Varg next()
276  {
277  if (_current >= _end)
278  return Varg::nil();
279  Varg a;
280  a.tag(*_current++);
281  a.data(reinterpret_cast<char const *>(_current));
282  _current += Msg::align_to<l4_umword_t>(a.length()) / sizeof(l4_umword_t);
283  if (_current > _end)
284  return Varg::nil();
285 
286  return a;
287  }
288 };
289 
290 /**
291  * Self-contained list of variable-sized RPC parameters.
292  *
293  * Works like Varg_list_ref but contains a full copy of the data.
294  * Use this as a parameter in server functions, if the handler function
295  * needs to use the UTCB (e.g. while sending further IPC).
296  */
297 template<unsigned MAX>
298 class Varg_list : public Varg_list_ref
299 {
300  l4_umword_t data[MAX];
301  Varg_list(Varg_list const &);
302 
303 public:
304  /// Create a parameter list as a copy from a referencing list.
305  Varg_list(Varg_list_ref const &r)
306  {
307  for (unsigned i = 0; i < r._end - r._current; ++i)
308  data[i] = r._current[i];
309 
310  this->_current = data;
311  this->_end = data + (r._end - r._current);
312  }
313 };
314 
315 
316 namespace Msg {
317 template<> struct Elem<Varg const *>
318 {
319  typedef Varg const *arg_type;
320  typedef Varg_list_ref svr_type;
321  typedef Varg_list_ref svr_arg_type;
322  enum { Is_optional = false };
323 };
324 
325 template<> struct Is_valid_rpc_type<Varg> : L4::Types::False {};
326 template<> struct Is_valid_rpc_type<Varg *> : L4::Types::False {};
327 template<> struct Is_valid_rpc_type<Varg &> : L4::Types::False {};
328 template<> struct Is_valid_rpc_type<Varg const &> : L4::Types::False {};
329 
330 template<> struct Direction<Varg const *> : Dir_in {};
331 template<> struct Class<Varg const *> : Cls_data {};
332 
333 template<typename DIR, typename CLASS>
334 struct Clnt_val_ops<Varg, DIR, CLASS>;
335 
336 template<>
337 struct Clnt_val_ops<Varg, Dir_in, Cls_data> :
338  Clnt_noops<Varg const &>
339 {
340  using Clnt_noops<Varg const &>::to_msg;
341  static int to_msg(char *msg, unsigned offs, unsigned limit,
342  Varg const &a, Dir_in, Cls_data)
343  {
344  for (Varg const *i = &a; i->tag(); ++i)
345  {
346  offs = align_to<l4_umword_t>(offs);
347  if (L4_UNLIKELY(!check_size<l4_umword_t>(offs, limit)))
348  return -L4_EMSGTOOLONG;
349  *reinterpret_cast<l4_umword_t*>(msg + offs) = i->tag();
350  offs += sizeof(l4_umword_t);
351  if (L4_UNLIKELY(!check_size<char>(offs, limit, i->length())))
352  return -L4_EMSGTOOLONG;
353  char const *d = i->data();
354  for (unsigned x = 0; x < i->length(); ++x)
355  msg[offs++] = *d++;
356  }
357 
358  return offs;
359  }
360 };
361 
362 template<>
363 struct Svr_val_ops<Varg_list_ref, Dir_in, Cls_data> :
364  Svr_noops<Varg_list_ref>
365 {
366  using Svr_noops<Varg_list_ref>::to_svr;
367  static int to_svr(char *msg, unsigned offset, unsigned limit,
368  Varg_list_ref &a, Dir_in, Cls_data)
369  {
370  unsigned start = align_to<l4_umword_t>(offset);
371  unsigned offs;
372  for (offs = start; offs < limit;)
373  {
374  unsigned noffs = align_to<l4_umword_t>(offs);
375  if (L4_UNLIKELY(!check_size<l4_umword_t>(noffs, limit)))
376  break;
377 
378  offs = noffs;
379  Varg arg;
380  arg.tag(*reinterpret_cast<l4_umword_t*>(msg + offs));
381 
382  if (!arg.tag())
383  break;
384 
385  offs += sizeof(l4_umword_t);
386 
387  if (L4_UNLIKELY(!check_size<char>(offs, limit, arg.length())))
388  return -L4_EMSGTOOLONG;
389  offs += arg.length();
390  }
391 
392  a = Varg_list_ref(msg + start, msg + align_to<l4_umword_t>(offs));
393  return offs;
394  }
395 };
396 }
397 }}