1// vi:set ft=cpp: -*- Mode: C++ -*- 2/** 3 * \file 4 * IPC stream 5 */ 6/* 7 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>, 8 * Alexander Warg <warg@os.inf.tu-dresden.de>, 9 * Torsten Frenzel <frenzel@os.inf.tu-dresden.de> 10 * economic rights: Technische Universität Dresden (Germany) 11 * 12 * This file is part of TUD:OS and distributed under the terms of the 13 * GNU General Public License 2. 14 * Please see the COPYING-GPL-2 file for details. 15 * 16 * As a special exception, you may use this file as part of a free software 17 * library without restriction. Specifically, if other files instantiate 18 * templates or use macros or inline functions from this file, or you compile 19 * this file and link it with other files to produce an executable, this 20 * file does not by itself cause the resulting executable to be covered by 21 * the GNU General Public License. This exception does not however 22 * invalidate any other reasons why the executable file might be covered by 23 * the GNU General Public License. 24 */ 25#pragma once 26 27#include <l4/sys/ipc.h> 28#include <l4/sys/capability> 29#include <l4/sys/cxx/ipc_types> 30#include <l4/sys/cxx/ipc_varg> 31#include <l4/cxx/type_traits> 32#include <l4/cxx/minmax> 33 34namespace L4 { 35namespace Ipc { 36 37class Ostream; 38class Istream; 39 40namespace Internal { 41/** 42 * Abstraction for inserting an array into an Ipc::Ostream. 43 * \internal 44 * 45 * An object of Buf_cp_out can be used to insert an array of arbitrary values, 46 * that can be inserted into an Ipc::Ostream individually. 47 * The array is therefore copied to the message buffer, in contrast to 48 * data handled with Msg_out_buffer or Msg_io_buffer. 49 * 50 * On insertion into the Ipc::Ostream exactly the given number of elements 51 * of type T are copied to the message buffer, this means the source buffer 52 * is no longer referenced after insertion into the stream. 53 * 54 * The method buf_cp_out() should be used to create instances of Buf_cp_out. 55 * 56 * The counterpart is either Buf_cp_in (buf_cp_in()) or Buf_in (buf_in()). 57 */ 58template< typename T > 59class Buf_cp_out 60{ 61public: 62 /** 63 * Create a buffer object for the given array. 64 * 65 * \param v The pointer to the array with size elements of type T. 66 * \param size The number of elements in the array. 67 */ 68 Buf_cp_out(T const *v, unsigned long size) : _v(v), _s(size) {} 69 70 /** 71 * Get the number of elements in the array. 72 * 73 * \return The number of elements in the array. 74 * 75 * \note This function is usually used by the Ipc::Ostream itself. 76 */ 77 unsigned long size() const { return _s; } 78 79 /** 80 * Get the pointer to the array. 81 * 82 * \return Pointer to the array. 83 * 84 * \note This function is usually used by the Ipc::Ostream itself. 85 */ 86 T const *buf() const { return _v; } 87 88private: 89 friend class Ostream; 90 T const *_v; 91 unsigned long _s; 92}; 93} 94 95/** 96 * Insert an array into an Ipc::Ostream. 97 * 98 * \param v Pointer to the array that shall be inserted into an 99 * Ipc::Ostream. 100 * \param size Number of elements in the array. 101 * 102 * This function inserts an array (e.g. a string) into an Ipc::Ostream. 103 * The data is copied to the stream. On insertion into the Ipc::Ostream 104 * exactly the given number of elements of type T are copied to the message 105 * buffer, this means the source buffer is no longer referenced after 106 * insertion into the stream. 107 * 108 * \see The counterpart is either buf_cp_in() or buf_in(). 109 */ 110template< typename T > 111Internal::Buf_cp_out<T> buf_cp_out(T const *v, unsigned long size) 112{ return Internal::Buf_cp_out<T>(v, size); } 113 114 115namespace Internal { 116/** 117 * Abstraction for extracting array from an Ipc::Istream. 118 * \internal 119 * 120 * An instance of Buf_cp_in can be used to extract an array from 121 * an Ipc::Istream. This is the counterpart to the Buf_cp_out abstraction. 122 * The data from the received message is thereby copied to the given buffer 123 * and size is set to the number of elements found in the stream. 124 * To avoid the copy operation Buf_in may be used instead. 125 * 126 * \see buf_cp_in(), Buf_in, buf_in(), Buf_cp_out, and buf_cp_out(). 127 */ 128template< typename T > 129class Buf_cp_in 130{ 131public: 132 /** 133 * Create a buffer for extracting an array from an Ipc::Istream. 134 * 135 * \param v The buffer for array (copy in). 136 * \param[in,out] size Input: the number of elements the array can take at 137 * most <br> 138 * Output: the number of elements found in the stream. 139 */ 140 Buf_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {} 141 142 unsigned long &size() const { return *_s; } 143 T *buf() const { return _v; } 144 145private: 146 friend class Istream; 147 T *_v; 148 unsigned long *_s; 149}; 150} 151 152/** 153 * Extract an array from an Ipc::Istream. 154 * 155 * \param v Pointer to the array that shall receive the values from 156 * the Ipc::Istream. 157 * \param[in,out] size Input: the number of elements the array can take at 158 * most <br> 159 * Output: the number of elements found in the stream. 160 * 161 * buf_cp_in() can be used to extract an array from an Ipc::Istream. This is 162 * the counterpart buf_cp_out(). The data from the received message is 163 * thereby copied to the given buffer and size is set to the number of 164 * elements found in the stream. To avoid the copy operation buf_in() may be 165 * used instead. 166 * 167 * \see buf_in() and buf_cp_out(). 168 */ 169template< typename T > 170Internal::Buf_cp_in<T> buf_cp_in(T *v, unsigned long &size) 171{ return Internal::Buf_cp_in<T>(v, size); } 172 173/** 174 * Abstraction for extracting a zero-terminated string from an Ipc::Istream. 175 * 176 * An instance of Str_cp_in can be used to extract a zero-terminated string 177 * an Ipc::Istream. The data from the received message is thereby copied to the 178 * given buffer and size is set to the number of characters found in the 179 * stream. The string is zero terminated in any circumstances. When the given 180 * buffer is smaller than the received string the last byte in the buffer will 181 * be the zero terminator. In the case the received string is shorter than the 182 * given buffer the zero termination will be placed behind the received data. 183 * This provides a zero-terminated result even in cases where the sender did 184 * not provide proper termination or in cases of too small receiver buffers. 185 * 186 * \see str_cp_in(). 187 */ 188template< typename T > 189class Str_cp_in 190{ 191public: 192 /** 193 * Create a buffer for extracting an array from an Ipc::Istream. 194 * 195 * \param v The buffer for string. 196 * \param[in,out] size Input: The number of bytes available in `v` <br> 197 * Output: The number of bytes received (including the 198 * terminator). 199 */ 200 Str_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {} 201 202 unsigned long &size() const { return *_s; } 203 T *buf() const { return _v; } 204 205private: 206 friend class Istream; 207 T *_v; 208 unsigned long *_s; 209}; 210 211/** 212 * Create a Str_cp_in for the given values. 213 * 214 * \param v Pointer to the array that shall receive the values from 215 * the Ipc::Istream. 216 * \param[in,out] size Input: the number of elements the array can take at 217 * most <br> 218 * Output: the number of elements found in the stream. 219 * 220 * This function makes it more convenient to extract arrays from an 221 * Ipc::Istream (\see Str_cp_in.) 222 */ 223template< typename T > 224Str_cp_in<T> str_cp_in(T *v, unsigned long &size) 225{ return Str_cp_in<T>(v, size); } 226 227/** 228 * Pointer to an element of type T in an Ipc::Istream. 229 * 230 * This wrapper can be used to extract an element of type T from an 231 * Ipc::Istream, whereas the data is not copied out, but a pointer into 232 * the message buffer itself is returned. With is mechanism it is possible 233 * to avoid an extra copy of large data structures from a received IPC 234 * message, instead the returned pointer gives direct access to the data 235 * in the message. 236 * 237 * See msg_ptr(). 238 */ 239template< typename T > 240class Msg_ptr 241{ 242private: 243 T **_p; 244public: 245 /** 246 * Create a Msg_ptr object that set pointer p to point into the message 247 * buffer. 248 * 249 * \param p The pointer that is adjusted to point into the message buffer. 250 */ 251 explicit Msg_ptr(T *&p) : _p(&p) {} 252 void set(T *p) const { *_p = p; } 253}; 254 255/** 256 * Create an Msg_ptr to adjust the given pointer. 257 * 258 * This function makes it more convenient to extract pointers to data in the 259 * message buffer itself from an Ipc::Istream. This may be used to avoid copy 260 * out of large data structures. (See Msg_ptr.) 261 */ 262template< typename T > 263Msg_ptr<T> msg_ptr(T *&p) 264{ return Msg_ptr<T>(p); } 265 266 267namespace Internal { 268/** 269 * Abstraction to extract an array from an Ipc::Istream. 270 * \internal 271 * 272 * This wrapper provides a possibility to extract an array from an 273 * Ipc::Istream, without extra copy overhead. In contrast to Buf_cp_in 274 * the data is not copied to a buffer, but a pointer to the array is returned. 275 * 276 * The mechanism is comparable to that of Msg_ptr, however it handles arrays 277 * inserted with Buf_cp_out. 278 * 279 * See buf_in(), Buf_cp_out, buf_cp_out(), Buf_cp_in, and buf_cp_in(). 280 */ 281template< typename T > 282class Buf_in 283{ 284public: 285 /** 286 * Create a Buf_in to adjust a pointer to the array and the size of the array. 287 * 288 * \param v The pointer to adjust to the first element of the array. 289 * \param[out] size The number of elements found in the stream. 290 */ 291 Buf_in(T *&v, unsigned long &size) : _v(&v), _s(&size) {} 292 293 void set_size(unsigned long s) const { *_s = s; } 294 T *&buf() const { return *_v; } 295 296private: 297 friend class Istream; 298 T **_v; 299 unsigned long *_s; 300}; 301} 302 303/** 304 * Return a pointer to stream array data. 305 * 306 * \param[out] v Pointer to the array within the Ipc::Istream. 307 * \param[out] size The number of elements found in the stream. 308 * 309 * This routine provdes a possibility to extract an array from an 310 * Ipc::Istream, without extra copy overhead. In contrast to buf_cp_in() 311 * the data is not copied to a buffer, but a pointer to the array is returned. 312 * The user must make sure the UTCB is not used for other purposes while the 313 * returned pointer is still in use. 314 * 315 * The mechanism is comparable to that of Msg_ptr, however it handles arrays 316 * inserted with buf_cp_out(). 317 * 318 * \see buf_cp_in() and buf_cp_out(). 319 */ 320template< typename T > 321Internal::Buf_in<T> buf_in(T *&v, unsigned long &size) 322{ return Internal::Buf_in<T>(v, size); } 323 324namespace Utcb_stream_check 325{ 326 static bool check_utcb_data_offset(unsigned sz) 327 { return sz > sizeof(l4_umword_t) * L4_UTCB_GENERIC_DATA_SIZE; } 328} 329 330 331/** 332 * Input stream for IPC unmarshalling. 333 * 334 * Ipc::Istream is part of the dynamic IPC marshalling infrastructure, as well 335 * as Ipc::Ostream and Ipc::Iostream. 336 * 337 * Ipc::Istream is an input stream supporting extraction of values from an 338 * IPC message buffer. A received IPC message can be unmarshalled using the 339 * usual extraction operator (>>). 340 * 341 * There exist some special wrapper classes to extract arrays (see 342 * Ipc_buf_cp_in and Ipc_buf_in) and indirect strings (see Msg_in_buffer and 343 * Msg_io_buffer). 344 */ 345class Istream 346{ 347public: 348 /** 349 * Create an input stream for the given message buffer. 350 * 351 * The given message buffer is used for IPC operations wait()/receive() 352 * and received data can be extracted using the >> operator afterwards. 353 * In the case of indirect message parts a buffer of type Msg_in_buffer 354 * must be inserted into the stream before the IPC operation and contains 355 * received data afterwards. 356 * 357 * \param utcb The message buffer to receive IPC messages. 358 */ 359 Istream(l4_utcb_t *utcb) 360 : _tag(), _utcb(utcb), 361 _current_msg(reinterpret_cast<char*>(l4_utcb_mr_u(utcb)->mr)), 362 _pos(0), _current_buf(0) 363 {} 364 365 /** 366 * Reset the stream to empty, and ready for receive()/wait(). 367 * The stream is reset to the same state as on its creation. 368 */ 369 void reset() 370 { 371 _pos = 0; 372 _current_buf = 0; 373 _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr); 374 } 375 376 /** 377 * Check whether a value of type T can be obtained from the stream. 378 */ 379 template< typename T > 380 bool has_more(unsigned long count = 1) 381 { 382 auto const max_bytes = L4_UTCB_GENERIC_DATA_SIZE * sizeof(l4_umword_t); 383 unsigned apos = cxx::Type_traits<T>::align(_pos); 384 return (count <= max_bytes / sizeof(T)) 385 && (apos + (sizeof(T) * count) 386 <= _tag.words() * sizeof(l4_umword_t)); 387 } 388 389 /** 390 * \name Get/Put Functions. 391 */ 392 //@{ 393 394 /** 395 * Copy out an array of type `T` with `size` elements. 396 * 397 * \param buf Pointer to a buffer for size elements of type T. 398 * \param elems Number of elements of type T to copy out. 399 * 400 * \return The number of elements copied out. 401 * 402 * See \ref Istream::operator>>() 403 */ 404 template< typename T > 405 unsigned long get(T *buf, unsigned long elems) 406 { 407 if (L4_UNLIKELY(!has_more<T>(elems))) 408 return 0; 409 410 unsigned long size = elems * sizeof(T); 411 _pos = cxx::Type_traits<T>::align(_pos); 412 413 __builtin_memcpy(buf, _current_msg + _pos, size); 414 _pos += size; 415 return elems; 416 } 417 418 419 /** 420 * Skip size elements of type T in the stream. 421 * 422 * \param elems Number of elements to skip. 423 */ 424 template< typename T > 425 void skip(unsigned long elems) 426 { 427 if (L4_UNLIKELY(!has_more<T>(elems))) 428 return; 429 430 unsigned long size = elems * sizeof(T); 431 _pos = cxx::Type_traits<T>::align(_pos); 432 _pos += size; 433 } 434 435 /** 436 * Read one size elements of type T from the stream and return a pointer. 437 * 438 * \param buf A Msg_ptr that is actually set to point to the element in the 439 * stream. 440 * \param elems Number of elements to extract (default is 1). 441 * 442 * \return The number of elements extracted. 443 * 444 * In contrast to a normal get, this version does actually not copy the data 445 * but returns a pointer to the data. 446 * 447 * See \ref Istream::operator>>() 448 */ 449 template< typename T > 450 unsigned long get(Msg_ptr<T> const &buf, unsigned long elems = 1) 451 { 452 if (L4_UNLIKELY(!has_more<T>(elems))) 453 return 0; 454 455 unsigned long size = elems * sizeof(T); 456 _pos = cxx::Type_traits<T>::align(_pos); 457 458 buf.set(reinterpret_cast<T*>(_current_msg + _pos)); 459 _pos += size; 460 return elems; 461 } 462 463 464 /** 465 * Extract a single element of type T from the stream. 466 * 467 * \param[out] v The element. 468 * 469 * \retval true An element was successfully extracted. 470 * \retval false An element could not be extracted. 471 * 472 * See \ref Istream::operator>>() 473 */ 474 template< typename T > 475 bool get(T &v) 476 { 477 if (L4_UNLIKELY(!has_more<T>())) 478 { 479 v = T(); 480 return false; 481 } 482 483 _pos = cxx::Type_traits<T>::align(_pos); 484 v = *(reinterpret_cast<T*>(_current_msg + _pos)); 485 _pos += sizeof(T); 486 return true; 487 } 488 489 490 bool get(Ipc::Varg *va) 491 { 492 Ipc::Varg::Tag t; 493 if (!has_more<Ipc::Varg::Tag>()) 494 { 495 va->tag(0); 496 return 0; 497 } 498 get(t); 499 va->tag(t); 500 char const *d; 501 get(msg_ptr(d), va->length()); 502 va->data(d); 503 504 return 1; 505 } 506 507 /** 508 * Get the message tag of a received IPC. 509 * 510 * \return The L4 message tag for the received IPC. 511 * 512 * This is in particular useful for handling page faults or exceptions. 513 * 514 * See \ref Istream::operator>>() 515 */ 516 l4_msgtag_t tag() const { return _tag; } 517 518 519 /** 520 * Get the message tag of a received IPC. 521 * 522 * \return A reference to the L4 message tag for the received IPC. 523 * 524 * This is in particular useful for handling page faults or exceptions. 525 * 526 * See \ref Istream::operator>>() 527 */ 528 l4_msgtag_t &tag() { return _tag; } 529 530 //@} 531 532 /** 533 * \internal 534 * Put a receive item into the stream's buffer registers. 535 */ 536 inline bool put(Buf_item const &); 537 538 /** 539 * \internal 540 * Put a small receive item into the stream's buffer registers. 541 */ 542 inline bool put(Small_buf const &); 543 544 545 /** 546 * \name IPC operations. 547 */ 548 //@{ 549 550 /** 551 * Wait for an incoming message from any sender. 552 * 553 * \param[out] src Contains the sender after a successful IPC operation. 554 * 555 * \return Syscall return tag. 556 * 557 * This wait is actually known as 'open wait'. 558 */ 559 inline l4_msgtag_t wait(l4_umword_t *src) 560 { return wait(src, L4_IPC_NEVER); } 561 562 /** 563 * Wait for an incoming message from any sender. 564 * 565 * \param[out] src Contains the sender after a successful IPC operation. 566 * \param timeout Timeout used for IPC. 567 * 568 * \return The IPC result tag (l4_msgtag_t). 569 * 570 * This wait is actually known as 'open wait'. 571 */ 572 inline l4_msgtag_t wait(l4_umword_t *src, l4_timeout_t timeout); 573 574 /** 575 * Wait for a message from the specified sender. 576 * 577 * \param src The sender id to receive from. 578 * 579 * \return The IPC result tag (l4_msgtag_t). 580 * 581 * This is commonly known as 'closed wait'. 582 */ 583 inline l4_msgtag_t receive(l4_cap_idx_t src) 584 { return receive(src, L4_IPC_NEVER); } 585 inline l4_msgtag_t receive(l4_cap_idx_t src, l4_timeout_t timeout); 586 587 //@} 588 589 /** 590 * Return utcb pointer. 591 */ 592 inline l4_utcb_t *utcb() const { return _utcb; } 593 594protected: 595 l4_msgtag_t _tag; 596 l4_utcb_t *_utcb; 597 char *_current_msg; 598 unsigned _pos; 599 unsigned char _current_buf; 600}; 601 602class Istream_copy : public Istream 603{ 604private: 605 l4_msg_regs_t _mrs; 606 607public: 608 Istream_copy(Istream const &o) : Istream(o), _mrs(*l4_utcb_mr_u(o.utcb())) 609 { 610 // do some reverse mr to utcb trickery 611 _utcb = (l4_utcb_t *)((l4_addr_t)&_mrs - (l4_addr_t)l4_utcb_mr_u((l4_utcb_t *)0)); 612 _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr); 613 } 614 615}; 616 617/** 618 * Output stream for IPC marshalling. 619 * 620 * Ipc::Ostream is part of the dynamic IPC marshalling infrastructure, as well 621 * as Ipc::Istream and Ipc::Iostream. 622 * 623 * Ipc::Ostream is an output stream supporting insertion of values into an 624 * IPC message buffer. A IPC message can be marshalled using the 625 * usual insertion operator <<, see \link ipc_stream IPC stream operators 626 * \endlink. 627 * 628 * There exist some special wrapper classes to insert arrays (see 629 * Ipc::Buf_cp_out) and indirect strings (see Msg_out_buffer and 630 * Msg_io_buffer). 631 */ 632class Ostream 633{ 634public: 635 /** 636 * Create an IPC output stream using the given message buffer `utcb`. 637 */ 638 Ostream(l4_utcb_t *utcb) 639 : _tag(), _utcb(utcb), 640 _current_msg(reinterpret_cast<char *>(l4_utcb_mr_u(_utcb)->mr)), 641 _pos(0), _current_item(0) 642 {} 643 644 /** 645 * Reset the stream to empty, same state as a newly created stream. 646 */ 647 void reset() 648 { 649 _pos = 0; 650 _current_item = 0; 651 _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr); 652 } 653 654 /** 655 * \name Get/Put functions. 656 * 657 * These functions are basically used to implement the insertion operators 658 * (<<) and should not be called directly. 659 */ 660 //@{ 661 662 /** 663 * Put an array with `size` elements of type `T` into the stream. 664 * 665 * \param buf A pointer to the array to insert into the buffer. 666 * \param size The number of elements in the array. 667 */ 668 template< typename T > 669 bool put(T *buf, unsigned long size) 670 { 671 size *= sizeof(T); 672 _pos = cxx::Type_traits<T>::align(_pos); 673 if (Utcb_stream_check::check_utcb_data_offset(_pos + size)) 674 return false; 675 676 __builtin_memcpy(_current_msg + _pos, buf, size); 677 _pos += size; 678 return true; 679 } 680 681 /** 682 * Insert an element of type `T` into the stream. 683 * 684 * \param v The element to insert. 685 */ 686 template< typename T > 687 bool put(T const &v) 688 { 689 _pos = cxx::Type_traits<T>::align(_pos); 690 if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T))) 691 return false; 692 693 *(reinterpret_cast<T*>(_current_msg + _pos)) = v; 694 _pos += sizeof(T); 695 return true; 696 } 697 698 int put(Varg const &va) 699 { 700 put(va.tag()); 701 put(va.data(), va.length()); 702 703 return 0; 704 } 705 706 template< typename T > 707 int put(Varg_t<T> const &va) 708 { return put(static_cast<Varg const &>(va)); } 709 710 /** 711 * Extract the L4 message tag from the stream. 712 * 713 * \return The extracted L4 message tag. 714 */ 715 l4_msgtag_t tag() const { return _tag; } 716 717 /** 718 * Extract a reference to the L4 message tag from the stream. 719 * 720 * \return A reference to the L4 message tag. 721 */ 722 l4_msgtag_t &tag() { return _tag; } 723 724 //@} 725 726 /** 727 * \internal 728 * Put a send item into the stream's message buffer. 729 */ 730 inline bool put_snd_item(Snd_item const &); 731 732 733 /** 734 * \name IPC operations. 735 */ 736 //@{ 737 738 /** 739 * Send the message via IPC to the given receiver. 740 * 741 * \param dst The destination for the message. 742 * \param proto Protocol to use. 743 * \param flags Flags to use. 744 * 745 * \return The syscall return tag. 746 */ 747 inline l4_msgtag_t send(l4_cap_idx_t dst, long proto = 0, unsigned flags = 0); 748 749 //@} 750 751 /** 752 * Return utcb pointer. 753 */ 754 inline l4_utcb_t *utcb() const { return _utcb; } 755#if 0 756 /** 757 * Get the currently used bytes in the stream. 758 */ 759 unsigned long tell() const 760 { 761 unsigned w = (_pos + sizeof(l4_umword_t)-1) / sizeof(l4_umword_t); 762 w -= _current_item * 2; 763 _tag = l4_msgtag(0, w, _current_item, 0); 764 } 765#endif 766public: 767 l4_msgtag_t prepare_ipc(long proto = 0, unsigned flags = 0) 768 { 769 unsigned w = (_pos + sizeof(l4_umword_t) - 1) / sizeof(l4_umword_t); 770 w -= _current_item * 2; 771 return l4_msgtag(proto, w, _current_item, flags); 772 } 773 774 // XXX: this is a hack for <l4/sys/cxx/ipc_server> adaption 775 void set_ipc_params(l4_msgtag_t tag) 776 { 777 _pos = (tag.words() + tag.items() * 2) * sizeof(l4_umword_t); 778 _current_item = tag.items(); 779 } 780protected: 781 l4_msgtag_t _tag; 782 l4_utcb_t *_utcb; 783 char *_current_msg; 784 unsigned _pos; 785 unsigned char _current_item; 786}; 787 788 789/** 790 * Input/Output stream for IPC [un]marshalling. 791 * 792 * The Ipc::Iostream is part of the AW Env IPC framework as well as 793 * Ipc::Istream and Ipc::Ostream. 794 * In particular an Ipc::Iostream is a combination of an Ipc::Istream and an 795 * Ipc::Ostream. It can use either a single message buffer for receiving and 796 * sending messages or a pair of a receive and a send buffer. The stream also 797 * supports combined IPC operations such as call() and reply_and_wait(), which 798 * can be used to implement RPC functionality. 799 */ 800class Iostream : public Istream, public Ostream 801{ 802public: 803 804 /** 805 * Create an IPC IO stream with a single message buffer. 806 * 807 * \param utcb The message buffer used as backing store. 808 * 809 * The created IO stream uses the same message buffer for sending and 810 * receiving IPC messages. 811 */ 812 explicit Iostream(l4_utcb_t *utcb) 813 : Istream(utcb), Ostream(utcb) 814 {} 815 816 // disambiguate those functions 817 l4_msgtag_t tag() const { return Istream::tag(); } 818 l4_msgtag_t &tag() { return Istream::tag(); } 819 l4_utcb_t *utcb() const { return Istream::utcb(); } 820 821 /** 822 * Reset the stream to its initial state. 823 * 824 * Input as well as the output stream are reset. 825 */ 826 void reset() 827 { 828 Istream::reset(); 829 Ostream::reset(); 830 } 831 832 833 /** 834 * \name Get/Put functions. 835 * 836 * These functions are basically used to implement the insertion operators 837 * (<<) and should not be called directly. 838 */ 839 //@{ 840 841 using Istream::get; 842 using Istream::put; 843 using Ostream::put; 844 845 //@} 846 847 /** 848 * \name IPC operations. 849 */ 850 //@{ 851 852 /** 853 * Do an IPC call using the message in the output stream and receive the 854 * reply in the input stream. 855 * 856 * \param dst The destination to call. 857 * \param timeout The IPC timeout for the call. 858 * \param proto The protocol value to use in the message tag. 859 * 860 * \return The result tag of the IPC operation. 861 * 862 * This is a combined IPC operation consisting of a send and a receive 863 * to/from the given destination `dst`. 864 * 865 * A call is usually used by clients for RPCs to a server. 866 */ 867 inline l4_msgtag_t call(l4_cap_idx_t dst, l4_timeout_t timeout, long proto = 0); 868 inline l4_msgtag_t call(l4_cap_idx_t dst, long proto = 0); 869 870 /** 871 * Do an IPC reply and wait. 872 * 873 * \param[in,out] src_dst Input: the destination for the send operation. <br> 874 * Output: the source of the received message. 875 * \param proto Protocol to use. 876 * 877 * \return The result tag of the IPC operation. 878 * 879 * This is a combined IPC operation consisting of a send operation and 880 * an open wait for any message. 881 * 882 * A reply and wait is usually used by servers that reply to a client 883 * and wait for the next request by any other client. 884 */ 885 inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst, long proto = 0) 886 { return reply_and_wait(src_dst, L4_IPC_SEND_TIMEOUT_0, proto); } 887 888 inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src, 889 long proto = 0) 890 { return send_and_wait(dest, src, L4_IPC_SEND_TIMEOUT_0, proto); } 891 892 /** 893 * Do an IPC reply and wait. 894 * 895 * \param[in,out] src_dst Input: the destination for the send operation. <br> 896 * Output: the source of the received message. 897 * \param timeout Timeout used for IPC. 898 * \param proto Protocol to use. 899 * 900 * \return The result tag of the IPC operation. 901 * 902 * This is a combined IPC operation consisting of a send operation and 903 * an open wait for any message. 904 * 905 * A reply and wait is usually used by servers that reply to a client 906 * and wait for the next request by any other client. 907 */ 908 inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst, 909 l4_timeout_t timeout, long proto = 0); 910 inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src, 911 l4_timeout_t timeout, long proto = 0); 912 inline l4_msgtag_t reply(l4_timeout_t timeout, long proto = 0); 913 inline l4_msgtag_t reply(long proto = 0) 914 { return reply(L4_IPC_SEND_TIMEOUT_0, proto); } 915 916 //@} 917}; 918 919 920inline bool 921Ostream::put_snd_item(Snd_item const &v) 922{ 923 typedef Snd_item T; 924 _pos = cxx::Type_traits<Snd_item>::align(_pos); 925 if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T))) 926 return false; 927 928 *(reinterpret_cast<T*>(_current_msg + _pos)) = v; 929 _pos += sizeof(T); 930 ++_current_item; 931 return true; 932} 933 934 935inline bool 936Istream::put(Buf_item const &item) 937{ 938 if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 3) 939 return false; 940 941 l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK; 942 943 reinterpret_cast<Buf_item&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item; 944 _current_buf += 2; 945 return true; 946} 947 948 949inline bool 950Istream::put(Small_buf const &item) 951{ 952 if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 2) 953 return false; 954 955 l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK; 956 957 reinterpret_cast<Small_buf&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item; 958 _current_buf += 1; 959 return true; 960} 961 962 963inline l4_msgtag_t 964Ostream::send(l4_cap_idx_t dst, long proto, unsigned flags) 965{ 966 l4_msgtag_t tag = prepare_ipc(proto, L4_MSGTAG_FLAGS & flags); 967 return l4_ipc_send(dst, _utcb, tag, L4_IPC_NEVER); 968} 969 970inline l4_msgtag_t 971Iostream::call(l4_cap_idx_t dst, l4_timeout_t timeout, long label) 972{ 973 l4_msgtag_t tag = prepare_ipc(label); 974 tag = l4_ipc_call(dst, Ostream::_utcb, tag, timeout); 975 Istream::tag() = tag; 976 Istream::_pos = 0; 977 return tag; 978} 979 980inline l4_msgtag_t 981Iostream::call(l4_cap_idx_t dst, long label) 982{ return call(dst, L4_IPC_NEVER, label); } 983 984 985inline l4_msgtag_t 986Iostream::reply_and_wait(l4_umword_t *src_dst, l4_timeout_t timeout, long proto) 987{ 988 l4_msgtag_t tag = prepare_ipc(proto); 989 tag = l4_ipc_reply_and_wait(Ostream::_utcb, tag, src_dst, timeout); 990 Istream::tag() = tag; 991 Istream::_pos = 0; 992 return tag; 993} 994 995 996inline l4_msgtag_t 997Iostream::send_and_wait(l4_cap_idx_t dest, l4_umword_t *src, 998 l4_timeout_t timeout, long proto) 999{ 1000 l4_msgtag_t tag = prepare_ipc(proto); 1001 tag = l4_ipc_send_and_wait(dest, Ostream::_utcb, tag, src, timeout); 1002 Istream::tag() = tag; 1003 Istream::_pos = 0; 1004 return tag; 1005} 1006 1007inline l4_msgtag_t 1008Iostream::reply(l4_timeout_t timeout, long proto) 1009{ 1010 l4_msgtag_t tag = prepare_ipc(proto); 1011 tag = l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, Ostream::_utcb, tag, timeout); 1012 Istream::tag() = tag; 1013 Istream::_pos = 0; 1014 return tag; 1015} 1016 1017inline l4_msgtag_t 1018Istream::wait(l4_umword_t *src, l4_timeout_t timeout) 1019{ 1020 l4_msgtag_t res; 1021 res = l4_ipc_wait(_utcb, src, timeout); 1022 tag() = res; 1023 _pos = 0; 1024 return res; 1025} 1026 1027 1028inline l4_msgtag_t 1029Istream::receive(l4_cap_idx_t src, l4_timeout_t timeout) 1030{ 1031 l4_msgtag_t res; 1032 res = l4_ipc_receive(src, _utcb, timeout); 1033 tag() = res; 1034 _pos = 0; 1035 return res; 1036} 1037 1038} // namespace Ipc 1039} // namespace L4 1040 1041/** 1042 * Extract one element of type `T` from the stream `s`. 1043 * 1044 * \param s The stream to extract from. 1045 * \param[out] v Extracted value. 1046 * 1047 * \return The stream `s`. 1048 */ 1049inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, bool &v) { s.get(v); return s; } 1050inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, int &v) { s.get(v); return s; } 1051inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long int &v) { s.get(v); return s; } 1052inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long long int &v) { s.get(v); return s; } 1053inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned int &v) { s.get(v); return s; } 1054inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long int &v) { s.get(v); return s; } 1055inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long long int &v) { s.get(v); return s; } 1056inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, short int &v) { s.get(v); return s; } 1057inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned short int &v) { s.get(v); return s; } 1058inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, char &v) { s.get(v); return s; } 1059inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned char &v) { s.get(v); return s; } 1060inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, signed char &v) { s.get(v); return s; } 1061inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Buf_item const &v) { s.put(v); return s; } 1062inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Small_buf const &v) { s.put(v); return s; } 1063inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Snd_item &v) 1064{ 1065 l4_umword_t b, d; 1066 s >> b >> d; 1067 v = L4::Ipc::Snd_item(b, d); 1068 return s; 1069} 1070inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Varg &v) 1071{ s.get(&v); return s; } 1072 1073 1074/** 1075 * Extract the L4 message tag from the stream `s`. 1076 * 1077 * \param s The stream to extract from. 1078 * \param[out] v The extracted tag. 1079 * 1080 * \return The stream `s`. 1081 */ 1082inline 1083L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, l4_msgtag_t &v) 1084{ 1085 v = s.tag(); 1086 return s; 1087} 1088 1089/** 1090 * Extract an array of `T` elements from the stream `s`. 1091 * 1092 * \param s The stream to extract from. 1093 * \param[out] v Pointer to the extracted array (ipc_buf_in()). 1094 * 1095 * \return The stream `s`. 1096 * 1097 * This operator actually does not copy out the data in the array, but 1098 * returns a pointer into the message buffer itself. This means that the 1099 * data is only valid as long as there is no new data inserted into the stream. 1100 * 1101 * \note If array does not fit into transmitted words size will be set to zero. 1102 * Client has to implement check against zero. 1103 * 1104 * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out. 1105 */ 1106template< typename T > 1107inline 1108L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, 1109 L4::Ipc::Internal::Buf_in<T> const &v) 1110{ 1111 unsigned long si; 1112 if (s.get(si) && s.has_more<T>(si)) 1113 v.set_size(s.get(L4::Ipc::Msg_ptr<T>(v.buf()), si)); 1114 else 1115 v.set_size(0); 1116 return s; 1117} 1118 1119/** 1120 * Extract an element of type `T` from the stream `s`. 1121 * 1122 * \param s The stream to extract from. 1123 * \param[out] v Pointer to the extracted element. 1124 * 1125 * \return The stream `s`. 1126 * 1127 * This operator actually does not copy out the data, but 1128 * returns a pointer into the message buffer itself. This means that the 1129 * data is only valid as long as there is no new data inserted into the stream. 1130 * 1131 * See Msg_ptr. 1132 */ 1133template< typename T > 1134inline 1135L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, 1136 L4::Ipc::Msg_ptr<T> const &v) 1137{ 1138 s.get(v); 1139 return s; 1140} 1141 1142/** 1143 * Extract an array of `T` elements from the stream `s`. 1144 * 1145 * \param s The stream to extract from. 1146 * \param[out] v Buffer description to copy the array to (Ipc::Buf_cp_out()). 1147 * 1148 * \return The stream `s`. 1149 * 1150 * This operator does a copy out of the data into the given buffer. 1151 * 1152 * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out. 1153 */ 1154template< typename T > 1155inline 1156L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, 1157 L4::Ipc::Internal::Buf_cp_in<T> const &v) 1158{ 1159 unsigned long sz; 1160 s.get(sz); 1161 v.size() = s.get(v.buf(), cxx::min(v.size(), sz)); 1162 return s; 1163} 1164 1165/** 1166 * Extract a zero-terminated string from the stream. 1167 * 1168 * \param s The stream to extract from. 1169 * \param[out] v Buffer description to copy the array to (Ipc::Str_cp_out()). 1170 * 1171 * \return The stream `s`. 1172 * 1173 * This operator does a copy out of the data into the given buffer. 1174 */ 1175template< typename T > 1176inline 1177L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, 1178 L4::Ipc::Str_cp_in<T> const &v) 1179{ 1180 unsigned long sz; 1181 s.get(sz); 1182 unsigned long rsz = s.get(v.buf(), cxx::min(v.size(), sz)); 1183 if (rsz < v.size() && v.buf()[rsz - 1]) 1184 ++rsz; // add the zero termination behind the received data 1185 1186 if (rsz != 0) 1187 v.buf()[rsz - 1] = 0; 1188 1189 v.size() = rsz; 1190 return s; 1191} 1192 1193 1194/** 1195 * Insert an element to type `T` into the stream `s`. 1196 * 1197 * \param s The stream to insert the element `v`. 1198 * \param v The element to insert. 1199 * 1200 * \return The stream `s`. 1201 */ 1202inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, bool v) { s.put(v); return s; } 1203inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, int v) { s.put(v); return s; } 1204inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long int v) { s.put(v); return s; } 1205inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long long int v) { s.put(v); return s; } 1206inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned int v) { s.put(v); return s; } 1207inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long int v) { s.put(v); return s; } 1208inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long long int v) { s.put(v); return s; } 1209inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, short int v) { s.put(v); return s; } 1210inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned short int v) { s.put(v); return s; } 1211inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char v) { s.put(v); return s; } 1212inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned char v) { s.put(v); return s; } 1213inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, signed char v) { s.put(v); return s; } 1214inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Snd_item const &v) { s.put_snd_item(v); return s; } 1215template< typename T > 1216inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Cap<T> const &v) 1217{ s << L4::Ipc::Snd_fpage(v.fpage()); return s; } 1218 1219inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg const &v) 1220{ s.put(v); return s; } 1221template< typename T > 1222inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg_t<T> const &v) 1223{ s.put(v); return s; } 1224 1225/** 1226 * Insert the L4 message tag into the stream `s`. 1227 * 1228 * \param s The stream to insert the tag `v`. 1229 * \param v The L4 message tag to insert. 1230 * 1231 * \return The stream `s`. 1232 * 1233 * \note Only one message tag can be inserted into a stream. Multiple 1234 * insertions simply overwrite previous insertions. 1235 */ 1236inline 1237L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, l4_msgtag_t const &v) 1238{ 1239 s.tag() = v; 1240 return s; 1241} 1242 1243/** 1244 * Insert an array with elements of type `T` into the stream `s`. 1245 * 1246 * \param s The stream to insert the array `v`. 1247 * \param v The array to insert (see Ipc::Buf_cp_out()). 1248 * 1249 * \return The stream `s`. 1250 */ 1251template< typename T > 1252inline 1253L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, 1254 L4::Ipc::Internal::Buf_cp_out<T> const &v) 1255{ 1256 s.put(v.size()); 1257 s.put(v.buf(), v.size()); 1258 return s; 1259} 1260 1261/** 1262 * Insert a zero terminated character string into the stream `s`. 1263 * 1264 * \param s The stream to insert the string `v`. 1265 * \param v The string to insert. 1266 * 1267 * \return The stream `s`. 1268 * 1269 * This operator produces basically the same content as the array insertion, 1270 * however the length of the array is calculated using `strlen(v) + 1` 1271 * The string is copied into the message including the trailing zero. 1272 */ 1273inline 1274L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char const *v) 1275{ 1276 unsigned long l = __builtin_strlen(v) + 1; 1277 s.put(l); 1278 s.put(v, l); 1279 return s; 1280} 1281 1282namespace L4 { namespace Ipc { 1283/** 1284 * Read a value out of a stream. 1285 * 1286 * \param s An Istream. 1287 * 1288 * \return The value of type `T`. 1289 * 1290 * The stream position is progressed accordingly. 1291 */ 1292template< typename T > 1293inline 1294T read(Istream &s) { T t; s >> t; return t; } 1295 1296} // namespace Ipc 1297} // namespace L4 1298