Loading...
Searching...
No Matches
ipc_varg
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#pragma GCC system_header
#include "types"
#include "ipc_basics"
namespace L4 { namespace Ipc L4_EXPORT {
template< typename T, template <typename X> class B >
struct Generic_va_type : B<T>
{
enum { Id = B<T>::Id };
typedef B<T> ID;
typedef T const &Ret_value;
typedef T Value;
static Ret_value value(void const *d)
{ return *reinterpret_cast<Value const *>(d); }
static void const *addr_of(Value const &v) { return &v; }
static unsigned size(void const *) { return sizeof(T); }
static L4_varg_type unsigned_id()
{
return static_cast<L4_varg_type>(Id & ~L4_VARG_TYPE_SIGN);
}
static L4_varg_type signed_id()
{
return static_cast<L4_varg_type>(Id | L4_VARG_TYPE_SIGN);
}
static L4_varg_type id()
{
return static_cast<L4_varg_type>(Id);
}
};
template< typename T > struct Va_type_id;
template<> struct Va_type_id<l4_umword_t> { enum { Id = L4_VARG_TYPE_UMWORD }; };
template<> struct Va_type_id<l4_mword_t> { enum { Id = L4_VARG_TYPE_MWORD }; };
template<> struct Va_type_id<l4_fpage_t> { enum { Id = L4_VARG_TYPE_FPAGE }; };
template<> struct Va_type_id<void> { enum { Id = L4_VARG_TYPE_NIL }; };
template<> struct Va_type_id<char const *> { enum { Id = L4_VARG_TYPE_STRING }; };
template< typename T > struct Va_type;
template<> struct Va_type<l4_umword_t> : Generic_va_type<l4_umword_t, Va_type_id> {};
template<> struct Va_type<l4_mword_t> : Generic_va_type<l4_mword_t, Va_type_id> {};
template<> struct Va_type<l4_fpage_t> : Generic_va_type<l4_fpage_t, Va_type_id> {};
template<> struct Va_type<void>
{
typedef void Ret_value;
typedef void Value;
static void const *addr_of(void) { return 0; }
static void value(void const *) {}
static L4_varg_type id() { return L4_VARG_TYPE_NIL; }
static unsigned size(void const *) { return 0; }
};
template<> struct Va_type<char const *>
{
typedef char const *Ret_value;
typedef char const *Value;
static void const *addr_of(Value v) { return v; }
static L4_varg_type id() { return L4_VARG_TYPE_STRING; }
static unsigned size(void const *s)
{
char const *_s = reinterpret_cast<char const *>(s);
int l = 1;
while (*_s)
{
++_s; ++l;
}
return l;
}
static Ret_value value(void const *d) { return static_cast<char const *>(d); }
};
class Varg
{
private:
enum { Direct_data = 0x8000 };
l4_umword_t _tag;
char const *_d;
public:
typedef l4_umword_t Tag;
L4_varg_type type() const { return static_cast<L4_varg_type>(_tag & 0xff); }
unsigned length() const { return _tag >> 16; }
Tag tag() const { return _tag & ~Direct_data; }
void tag(Tag tag) { _tag = tag; }
void data(char const *d) { _d = d; }
char const *data() const
{
if (_tag & Direct_data)
{
union T { char const *d; char v[sizeof(char const *)]; };
return reinterpret_cast<T const *>(&_d)->v;
}
return _d;
}
#if __cplusplus >= 201103L
Varg() = default;
#else
Varg() {}
#endif
Varg(L4_varg_type t, void const *v, int len)
: _tag(t | (static_cast<l4_mword_t>(len) << 16)),
_d(static_cast<char const *>(v))
{}
static Varg nil() { return Varg(L4_VARG_TYPE_NIL, 0, 0); }
template< typename V >
typename Va_type<V>::Ret_value value() const
{
if (_tag & Direct_data)
{
union X { char const *d; V v; };
return reinterpret_cast<X const &>(_d).v;
}
return Va_type<V>::value(_d);
}
template< typename T >
bool is_of() const { return Va_type<T>::id() == type(); }
bool is_nil() const { return is_of<void>(); }
bool is_of_int() const
{ return (type() & ~L4_VARG_TYPE_SIGN) == L4_VARG_TYPE_UMWORD; }
template< typename T >
bool get_value(typename Va_type<T>::Value *v) const
{
if (!is_of<T>())
return false;
*v = this->value<T>();
return true;
}
template< typename T >
void set_value(void const *d)
{
typedef Va_type<T> Vt;
_tag = Vt::id() | (Vt::size(d) << 16);
_d = static_cast<char const *>(d);
}
template<typename T>
void set_direct_value(T val, typename L4::Types::Enable_if<sizeof(T) <= sizeof(char const *), bool>::type = true)
{
static_assert(sizeof(T) <= sizeof(char const *), "direct Varg value too big");
typedef Va_type<T> Vt;
_tag = Vt::id() | (sizeof(T) << 16) | Direct_data;
union X { char const *d; T v; };
reinterpret_cast<X &>(_d).v = val;
}
template<typename T> explicit
Varg(T const *data) { set_value<T>(data); }
Varg(char const *data) { set_value<char const *>(data); }
template<typename T> explicit
Varg(T data, typename L4::Types::Enable_if<sizeof(T) <= sizeof(char const *), bool>::type = true)
{ set_direct_value<T>(data); }
};
template<typename T>
class Varg_t : public Varg
{
public:
typedef typename Va_type<T>::Value Value;
explicit Varg_t(Value v) : Varg()
{ _data = v; set_value<T>(Va_type<T>::addr_of(_data)); }
private:
Value _data;
};
template<unsigned MAX = L4_UTCB_GENERIC_DATA_SIZE>
class Varg_list;
class Varg_list_ref
{
private:
template<unsigned T>
friend class Varg_list;
class Iter_state
{
private:
using M = l4_umword_t;
using Mp = M const *;
Mp _c;
Mp _e;
Mp next_arg(Varg const &a) const
{
return _c + 1 + (Msg::align_to<M>(a.length()) / sizeof(M));
}
public:
Iter_state() : _c(nullptr), _e(nullptr) {}
Iter_state(Mp c, Mp e) : _c(c), _e(e)
{}
bool valid() const
{ return _c && _c < _e; }
Mp begin() const { return _c; }
Mp end() const { return _e; }
Varg pop()
{
if (!valid())
return Varg::nil();
Varg a;
a.tag(_c[0]);
a.data(reinterpret_cast<char const *>(&_c[1]));
_c = next_arg(a);
if (_c > _e)
return Varg::nil();
return a;
}
bool operator == (Iter_state const &o) const
{ return _c == o._c; }
bool operator != (Iter_state const &o) const
{ return _c != o._c; }
};
Iter_state _s;
public:
Varg_list_ref() = default;
Varg_list_ref(void const *start, void const *end)
: _s(reinterpret_cast<l4_umword_t const *>(start),
reinterpret_cast<l4_umword_t const *>(end))
{}
class Iterator
{
private:
Iter_state _s;
Varg _a;
public:
Iterator(Iter_state const &s)
: _s(s)
{
_a = _s.pop();
}
explicit operator bool () const
{ return !_a.is_nil(); }
Iterator &operator ++ ()
{
if (!_a.is_nil())
_a = _s.pop();
return *this;
}
Varg operator * () const
{ return _a; }
bool equals(Iterator const &o) const
{
if (_a.is_nil() && o._a.is_nil())
return true;
return _s == o._s;
}
bool operator == (Iterator const &o) const
{ return equals(o); }
bool operator != (Iterator const &o) const
{ return !equals(o); }
};
Varg pop_front()
{ return _s.pop(); }
Varg next()
L4_DEPRECATED("Use range for or pop_front.")
{ return _s.pop(); }
Iterator begin() const
{ return Iterator(_s); }
Iterator end() const
{ return Iterator(Iter_state()); }
};
template<unsigned MAX>
class Varg_list : public Varg_list_ref
{
l4_umword_t data[MAX];
Varg_list(Varg_list const &);
public:
Varg_list(Varg_list_ref const &r)
{
if (!r._s.valid())
return;
l4_umword_t const *rs = r._s.begin();
unsigned c = r._s.end() - rs;
for (unsigned i = 0; i < c; ++i)
data[i] = rs[i];
this->_s = Iter_state(data, data + c);
}
};
namespace Msg {
template<> struct Elem<Varg const *>
{
typedef Varg const *arg_type;
typedef Varg_list_ref svr_type;
typedef Varg_list_ref svr_arg_type;
enum { Is_optional = false };
};
template<> struct Is_valid_rpc_type<Varg> : L4::Types::False {};
template<> struct Is_valid_rpc_type<Varg *> : L4::Types::False {};
template<> struct Is_valid_rpc_type<Varg &> : L4::Types::False {};
template<> struct Is_valid_rpc_type<Varg const &> : L4::Types::False {};
template<> struct Direction<Varg const *> : Dir_in {};
template<> struct Class<Varg const *> : Cls_data {};
template<typename DIR, typename CLASS>
struct Clnt_val_ops<Varg, DIR, CLASS>;
template<>
struct Clnt_val_ops<Varg, Dir_in, Cls_data> :
Clnt_noops<Varg const &>
{
using Clnt_noops<Varg const &>::to_msg;
static int to_msg(char *msg, unsigned offs, unsigned limit,
Varg const &a, Dir_in, Cls_data)
{
for (Varg const *i = &a; i->tag(); ++i)
{
offs = align_to<l4_umword_t>(offs);
if (L4_UNLIKELY(!check_size<l4_umword_t>(offs, limit)))
return -L4_EMSGTOOLONG;
*reinterpret_cast< l4_umword_t*>(msg + offs) = i->tag();
offs += sizeof(l4_umword_t);
if (L4_UNLIKELY(!check_size<char>(offs, limit, i->length())))
return -L4_EMSGTOOLONG;
char const *d = i->data();
for (unsigned x = 0; x < i->length(); ++x)
msg[offs++] = *d++;
}
return offs;
}
};
template<>
struct Svr_val_ops<Varg_list_ref, Dir_in, Cls_data> :
Svr_noops<Varg_list_ref>
{
using Svr_noops<Varg_list_ref>::to_svr;
static int to_svr(char *msg, unsigned offset, unsigned limit,
Varg_list_ref &a, Dir_in, Cls_data)
{
unsigned start = align_to<l4_umword_t>(offset);
unsigned offs;
for (offs = start; offs < limit;)
{
unsigned noffs = align_to<l4_umword_t>(offs);
if (L4_UNLIKELY(!check_size<l4_umword_t>(noffs, limit)))
break;
offs = noffs;
Varg arg;
arg.tag(*reinterpret_cast< l4_umword_t*>(msg + offs));
if (!arg.tag())
break;
offs += sizeof(l4_umword_t);
if (L4_UNLIKELY(!check_size<char>(offs, limit, arg.length())))
return -L4_EMSGTOOLONG;
offs += arg.length();
}
a = Varg_list_ref(msg + start, msg + align_to<l4_umword_t>(offs));
return offs;
}
};
}
}}
L4::Ipc::Varg_list_ref::Iterator
Iterator for Valists.
Definition ipc_varg:339
L4::Ipc::Varg_list_ref::Iterator::Iterator
Iterator(Iter_state const &s)
Create a new iterator.
Definition ipc_varg:346
L4::Ipc::Varg_list_ref::Iterator::equals
bool equals(Iterator const &o) const
check for equality
Definition ipc_varg:370
L4::Ipc::Varg_list_ref::Iterator::operator++
Iterator & operator++()
increment iterator to the next arg
Definition ipc_varg:357
L4::Ipc::Varg_list_ref::Iterator::operator*
Varg operator*() const
dereference the iterator, get Varg
Definition ipc_varg:366
L4::Ipc::Varg_list_ref::begin
Iterator begin() const
Returns an interator to the first Varg.
Definition ipc_varg:395
L4::Ipc::Varg_list_ref::pop_front
Varg pop_front()
Get the next parameter in the list.
Definition ipc_varg:386
L4::Ipc::Varg_list_ref::next
Varg next()
Get the next parameter in the list.
Definition ipc_varg:390
L4::Ipc::Varg_list_ref::Varg_list_ref
Varg_list_ref(void const *start, void const *end)
Create a parameter list over a given memory region.
Definition ipc_varg:332
L4::Ipc::Varg_list_ref::end
Iterator end() const
Returns the end of the list.
Definition ipc_varg:399
L4::Ipc::Varg_list_ref::Varg_list_ref
Varg_list_ref()=default
Create an empty parameter list.
L4::Ipc::Varg_list
Self-contained list of variable-sized RPC parameters.
Definition ipc_varg:412
L4::Ipc::Varg_list::Varg_list
Varg_list(Varg_list_ref const &r)
Create a parameter list as a copy from a referencing list.
Definition ipc_varg:418
L4::Ipc::Varg
Variably sized RPC argument.
Definition ipc_varg:97
L4::Ipc::Varg::is_of_int
bool is_of_int() const
Definition ipc_varg:175
L4::Ipc::Varg::Varg
Varg(char const *data)
Make Varg from null-terminated string.
Definition ipc_varg:218
L4::Ipc::Varg::data
char const * data() const
Definition ipc_varg:123
L4::Ipc::Varg::Varg
Varg(L4_varg_type t, void const *v, int len)
Make an indirect varg.
Definition ipc_varg:141
L4::Ipc::Varg::Varg
Varg()=default
Make uninitialized Varg.
L4::Ipc::Varg::Tag
l4_umword_t Tag
The data type for the tag.
Definition ipc_varg:106
L4::Ipc::Varg::value
Va_type< V >::Ret_value value() const
Definition ipc_varg:155
L4::Ipc::Varg::is_of
bool is_of() const
Definition ipc_varg:169
L4::Ipc::Varg::set_direct_value
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:205
L4::Ipc::Varg::length
unsigned length() const
Get the size of the RPC argument.
Definition ipc_varg:114
L4::Ipc::Varg::set_value
void set_value(void const *d)
Set to indirect value of type T.
Definition ipc_varg:196
L4::Ipc::Varg::tag
Tag tag() const
Definition ipc_varg:116
L4::Ipc::Varg::type
L4_varg_type type() const
Definition ipc_varg:109
L4::Ipc::Varg::tag
void tag(Tag tag)
Set Varg tag (usually from message).
Definition ipc_varg:118
L4::Ipc::Varg::Varg
Varg(T const *data)
Make Varg from indirect value (pointer).
Definition ipc_varg:216
L4::Ipc::Varg::Varg
Varg(T data, typename L4::Types::Enable_if< sizeof(T)<=sizeof(char const *), bool >::type=true)
Make Varg from direct value.
Definition ipc_varg:222
L4::Ipc::Varg::data
void data(char const *d)
Set Varg to indirect data value (usually in UTCB).
Definition ipc_varg:120
L4::Ipc::Varg::is_nil
bool is_nil() const
Definition ipc_varg:172
L4::Ipc::Varg::get_value
bool get_value(typename Va_type< T >::Value *v) const
Get the value of the Varg as type T.
Definition ipc_varg:185
l4_umword_t
unsigned long l4_umword_t
Unsigned machine word.
Definition l4int.h:40
l4_mword_t
signed long l4_mword_t
Signed machine word.
Definition l4int.h:37
L4_EMSGTOOLONG
@ L4_EMSGTOOLONG
Message too long.
Definition err.h:57
L4_UNLIKELY
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:284
L4_EXPORT
#define L4_EXPORT
Attribute to mark functions, variables, and data types as being exported from a library.
Definition compiler.h:214
L4_DEPRECATED
#define L4_DEPRECATED(s)
Mark symbol deprecated.
Definition compiler.h:289
L4::Ipc::Msg::check_size
constexpr bool check_size(unsigned offset, unsigned limit) noexcept
Check if there is enough space for T from offset to limit.
Definition ipc_basics:53
L4::Ipc::Msg::align_to
constexpr unsigned long align_to(unsigned long bytes, unsigned long align) noexcept
Pad bytes to the given alignment align (in bytes).
Definition ipc_basics:30
L4::Ipc
IPC related functionality.
Definition ipc_array:13
L4
L4 low-level kernel interface.
Definition l4sys-l4f-groups.dox:50
L4::Ipc::Msg::Cls_data
Marker type for data values.
Definition ipc_basics:150
L4::Ipc::Msg::Dir_in
Marker type for input values.
Definition ipc_basics:145
L4::Ipc::Msg::Is_valid_rpc_type
Type trait defining a valid RPC parameter type.
Definition ipc_basics:339
L4::Ipc::Msg::Svr_val_ops
Defines client-side handling of `MTYPE' as RPC argument.
Definition ipc_basics:264
types