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