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
24namespace L4 { namespace Ipc L4_EXPORT {
25
26template< typename T, template <typename X> class B >
27struct 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
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  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
71template<> 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 */
96class Varg
97{
98private:
99  enum { Direct_data = 0x8000 };
100  l4_umword_t _tag;
101  char const *_d;
102
103public:
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
226template<typename T>
227class Varg_t : public Varg
228{
229public:
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
234private:
235  Value _data;
236};
237
238template<unsigned MAX = L4_UTCB_GENERIC_DATA_SIZE>
239class 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 */
252class Varg_list_ref
253{
254private:
255  template<unsigned T>
256  friend class Varg_list;
257
258  /// Iterator state of a Varg list
259  class Iter_state
260  {
261  private:
262    using M = l4_umword_t; ///< internal shortcut for msg words
263    using Mp = M const *;  ///< internal shortcut for msg pointer
264    Mp _c; ///< current position of an iterator
265    Mp _e; ///< end of the message (first word behind)
266
267    /// get pointer to the start of the next Varg
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:
274    /// default (invalid/empty/end) state
275    Iter_state() : _c(nullptr) {}
276
277    /// create a state for varg at c, end at e
278    Iter_state(Mp c, Mp e) : _c(c), _e(e)
279    {}
280
281    /// return true if the state is valid (not end)
282    bool valid() const
283    { return _c && _c < _e; }
284
285    /// get the current position (of current Varg)
286    Mp begin() const { return _c; }
287
288    /// get the end of the message (behind last Varg)
289    Mp end() const { return _e; }
290
291    /**
292     * Pop the first Varg from the list
293     * (Varg::nil() if there are no more)
294     */
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
310    /// equality of two Iter_state objects
311    bool operator == (Iter_state const &o) const
312    { return _c == o._c; }
313
314    /// inequality of two Iter_state objects
315    bool operator != (Iter_state const &o) const
316    { return _c != o._c; }
317  };
318
319  Iter_state _s; ///< current state of the Valist
320
321public:
322  /// Create an empty parameter list.
323  Varg_list_ref() = default;
324
325  /**
326   *  Create a parameter list over a given memory region.
327   *
328   *  \param start Pointer to start of the parameter list.
329   *  \param end   Pointer to end of the list (inclusive).
330   */
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
336  /// Iterator for Valists
337  class Iterator
338  {
339  private:
340    Iter_state _s; ///< The current position (next unread arg)
341    Varg _a; ///< The current Varg read from the list
342
343  public:
344    /// Create a new iterator
345    Iterator(Iter_state const &s)
346    : _s(s)
347    {
348      _a = _s.pop();
349    }
350
351    /// validity check for the iterator
352    explicit operator bool () const
353    { return !_a.is_nil(); }
354
355    /// increment iterator to the next arg
356    Iterator &operator ++ ()
357    {
358      if (!_a.is_nil())
359        _a = _s.pop();
360
361      return *this;
362    }
363
364    /// dereference the iterator, get Varg
365    Varg operator * () const
366    { return _a; }
367
368    /// check for equality
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
384  /// Get the next parameter in the list.
385  Varg pop_front()
386  { return _s.pop(); }
387
388  /// Get the next parameter in the list.
389  Varg next()
390    L4_DEPRECATED("Use range for or pop_front.")
391  { return _s.pop(); }
392
393  /// Returns an interator to the first Varg
394  Iterator begin() const
395  { return Iterator(_s); }
396
397  /// Returns the end of the list
398  Iterator end() const
399  { return Iterator(Iter_state()); }
400};
401
402/**
403 * Self-contained list of variable-sized RPC parameters.
404 *
405 * Works like Varg_list_ref but contains a full copy of the data.
406 * Use this as a parameter in server functions, if the handler function
407 * needs to use the UTCB (e.g. while sending further IPC).
408 */
409template<unsigned MAX>
410class Varg_list : public Varg_list_ref
411{
412  l4_umword_t data[MAX];
413  Varg_list(Varg_list const &);
414
415public:
416  /// Create a parameter list as a copy from a referencing list.
417  Varg_list(Varg_list_ref const &r)
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
432namespace Msg {
433template<> 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
441template<> struct Is_valid_rpc_type<Varg> : L4::Types::False {};
442template<> struct Is_valid_rpc_type<Varg *> : L4::Types::False {};
443template<> struct Is_valid_rpc_type<Varg &> : L4::Types::False {};
444template<> struct Is_valid_rpc_type<Varg const &> : L4::Types::False {};
445
446template<> struct Direction<Varg const *> : Dir_in {};
447template<> struct Class<Varg const *> : Cls_data {};
448
449template<typename DIR, typename CLASS>
450struct Clnt_val_ops<Varg, DIR, CLASS>;
451
452template<>
453struct 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
478template<>
479struct 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}}
514