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)
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.
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.
28 #include <l4/sys/ipc.h>
29 #include <l4/sys/capability>
30 #include <l4/cxx/type_traits>
31 #include <l4/cxx/minmax>
33 #define L4_CXX_IPC_BACKWARD_COMPAT
46 * \brief Abstraction for inserting an array into an Ipc::Ostream.
50 * An object of Buf_cp_out can be used to insert an array of arbitrary values,
51 * that can be inserted into an Ipc::Ostream individually.
52 * The array is therefore copied to the message buffer, in contrast to
53 * data handled with Msg_out_buffer or Msg_io_buffer.
55 * On insertion into the Ipc::Ostream exactly the given number of elements
56 * of type T are copied to the message buffer, this means the source buffer
57 * is no longer referenced after insertion into the stream.
59 * You should use buf_cp_out() to create instances of Buf_cp_out.
61 * The counterpart is either Buf_cp_in (buf_cp_in()) or Buf_in (buf_in()).
63 template< typename T >
68 * \brief Create a buffer object for the given array.
69 * \param v The pointer to the array with size elements of type T.
70 * \param size the number of elements in the array.
72 Buf_cp_out(T const *v, unsigned long size) : _v(v), _s(size) {}
75 * \brief Get the number of elements in the array.
76 * \note This function is usually used by the Ipc::Ostream itself.
78 unsigned long size() const { return _s; }
81 * \brief Get the pointer to the array.
82 * \note This function is usually used by the Ipc::Ostream itself.
84 T const *buf() const { return _v; }
94 * \brief Insert an array into an Ipc::Ostream.
97 * \param v Pointer to the array that shall be inserted into an Ipc::Ostream.
98 * \param size Number of elements in the array.
100 * This function inserts an array (e.g. a string) into an Ipc::Ostream.
101 * The data is copied to the stream. On insertion into the Ipc::Ostream
102 * exactly the given number of elements of type T are copied to the message
103 * buffer, this means the source buffer is no longer referenced after
104 * insertion into the stream.
106 * \see The counterpart is either buf_cp_in() or buf_in().
108 template< typename T >
109 Internal::Buf_cp_out<T> buf_cp_out(T const *v, unsigned long size)
110 { return Internal::Buf_cp_out<T>(v, size); }
115 * \brief Abstraction for extracting array from an Ipc::Istream.
119 * An instance of Buf_cp_in can be used to extract an array from
120 * an Ipc::Istream. This is the counterpart to the Buf_cp_out abstraction.
121 * The data from the received message is thereby copied to the given buffer
122 * and size is set to the number of elements found in the stream.
123 * To avoid the copy operation Buf_in may be used instead.
125 * \see buf_cp_in(), Buf_in, buf_in(), Buf_cp_out, and buf_cp_out().
127 template< typename T >
132 * \brief Create a buffer for extracting an array from an Ipc::Istream.
133 * \param v The buffer for array (copy in).
134 * \param size Input: the number of elements the array can take at most<br>
135 * Output: the number of elements found in the stream.
137 Buf_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {}
139 unsigned long &size() const { return *_s; }
140 T *buf() const { return _v; }
142 friend class Istream;
149 * \brief Extract an array from an Ipc::Istream.
152 * \param v Pointer to the array that shall receive the values from the
154 * \param size Input: the number of elements the array can take at most<br>
155 * Output: the number of elements found in the stream.
157 * buf_cp_in() can be used to extract an array from an Ipc::Istream. This is
158 * the counterpart buf_cp_out(). The data from the received message is
159 * thereby copied to the given buffer and size is set to the number of
160 * elements found in the stream. To avoid the copy operation buf_in() may be
163 * \see buf_in() and buf_cp_out().
165 template< typename T >
166 Internal::Buf_cp_in<T> buf_cp_in(T *v, unsigned long &size)
167 { return Internal::Buf_cp_in<T>(v, size); }
170 * \brief Abstraction for extracting a zero-termintaed string from
174 * An instance of Str_cp_in can be used to extract a zero-terminated string
175 * an Ipc::Istream. The data from the received message is thereby copied to the
176 * given buffer and size is set to the number of characters found in the
177 * stream. The string is zero terminated in any circumstances. When the given
178 * buffer is smaller than the received string the last byte in the buffer will
179 * be the zero terminator. In the case the received string is shorter than the
180 * given buffer the zero termination will be placed behind the received data.
181 * This provides a zero-terminated result even in cases where the sender did
182 * not provide proper termination or in cases of too small receiver buffers.
186 template< typename T >
191 * \brief Create a buffer for extracting an array from an Ipc::Istream.
192 * \param v The buffer for string.
193 * \param[in] size the number of bytes available in \a v<br>
194 * \param[out] size the number of bytes received (including the terminator).
196 Str_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {}
198 unsigned long &size() const { return *_s; }
199 T *buf() const { return _v; }
201 friend class Istream;
207 * \brief Create a Str_cp_in for the given values.
210 * This function makes it more convenient to extract arrays from an
211 * Ipc::Istream (\see Str_cp_in.)
213 * \param v Pointer to the array that shall receive the values from the
215 * \param size Input: the number of elements the array can take at most<br>
216 * Output: the number of elements found in the stream.
218 template< typename T >
219 Str_cp_in<T> str_cp_in(T *v, unsigned long &size)
220 { return Str_cp_in<T>(v, size); }
223 * \brief Pointer to an element of type T in an Ipc::Istream.
226 * This wrapper can be used to extract an element of type T from an
227 * Ipc::Istream, whereas the data is not copied out, but a pointer into
228 * the message buffer itself is returned. With is mechanism it is possible
229 * to avoid an extra copy of large data structures from a received IPC
230 * message, instead the returned pointer gives direct access to the data
235 template< typename T >
242 * \brief Create a Msg_ptr object that set pointer p to point into the
244 * \param p The pointer that is adjusted to point into the message buffer.
246 explicit Msg_ptr(T *&p) : _p(&p) {}
247 void set(T *p) const { *_p = p; }
251 * \brief Create an Msg_ptr to adjust the given pointer.
254 * This function makes it more convenient to extract pointers to data in the
255 * message buffer itself from an Ipc::Istream.
256 * This may be used to avoid copy out of large data structures.
259 template< typename T >
260 Msg_ptr<T> msg_ptr(T *&p)
261 { return Msg_ptr<T>(p); }
266 * \brief Abstraction to extract an array from an Ipc::Istream.
270 * This wrapper provides a possibility to extract an array from an
271 * Ipc::Istream, without extra copy overhead. In contrast to Buf_cp_in
272 * the data is not copied to a buffer, but a pointer to the array is returned.
274 * The mechanism is comparable to that of Msg_ptr, however it handles arrays
275 * inserted with Buf_cp_out.
277 * See buf_in(), Buf_cp_out, buf_cp_out(), Buf_cp_in, and buf_cp_in().
279 template< typename T >
284 * \brief Create an Buf_in to adjust a pointer to the array and the size
286 * \param v The pointer to adjust to the first element of the array.
287 * \param size The number of elements found in the stream.
289 Buf_in(T *&v, unsigned long &size) : _v(&v), _s(&size) {}
291 void set_size(unsigned long s) const { *_s = s; }
292 T *&buf() const { return *_v; }
294 friend class Istream;
301 * \brief Return a pointer to stream array data.
304 * \param v Output: pointer to the array within the Ipc::Istream.
305 * \param size Output: the number of elements found in the stream.
307 * This routine provdes a possibility to extract an array from an
308 * Ipc::Istream, without extra copy overhead. In contrast to buf_cp_in()
309 * the data is not copied to a buffer, but a pointer to the array is returned.
310 * The user must make sure the UTCB is not used for other purposes while the
311 * returned pointer is still in use.
313 * The mechanism is comparable to that of Msg_ptr, however it handles arrays
314 * inserted with buf_cp_out().
316 * \see buf_cp_in() and buf_cp_out().
318 template< typename T >
319 Internal::Buf_in<T> buf_in(T *&v, unsigned long &size)
320 { return Internal::Buf_in<T>(v, size); }
325 * \brief A receive item for receiving a single capability.
327 * This class is the main abstraction for receiving capabilities
328 * via Ipc::Istream. To receive a capability an instance of Small_buf
329 * that refers to an empty capability slot must be inserted into the
330 * Ipc::Istream before the receive operation.
335 explicit Small_buf(L4::Cap<L4::Kobject> cap, unsigned long flags = 0)
336 : _data(cap.cap() | L4_RCV_ITEM_SINGLE_CAP | flags) {}
338 explicit Small_buf(l4_cap_idx_t idx, unsigned long flags = 0)
339 : _data(idx | L4_RCV_ITEM_SINGLE_CAP | flags) {}
347 Snd_item(l4_umword_t base, l4_umword_t data) : _base(base), _data(data) {}
357 Buf_item(l4_umword_t base, l4_umword_t data) : _base(base), _data(data) {}
364 template< typename T >
365 class Gen_fpage : public T
370 Special = L4_FPAGE_SPECIAL << 4,
371 Memory = L4_FPAGE_MEMORY << 4,
372 Io = L4_FPAGE_IO << 4,
373 Obj = L4_FPAGE_OBJ << 4
378 Map = L4_MAP_ITEM_MAP,
379 Grant = L4_MAP_ITEM_GRANT,
385 Cached = L4_FPAGE_CACHEABLE << 4,
386 Buffered = L4_FPAGE_BUFFERABLE << 4,
387 Uncached = L4_FPAGE_UNCACHEABLE << 4
395 Compound = L4_ITEM_CONT,
399 Gen_fpage(Type type, l4_addr_t base, int order,
400 unsigned char rights,
403 Cacheopt cache, Continue cont)
404 : T(L4_ITEM_MAP | (snd_base & (~0UL << 10)) | l4_umword_t(map_type) | l4_umword_t(cache)
406 base | l4_umword_t(type) | rights | (l4_umword_t(order) << 6))
410 Gen_fpage() : T(0, 0) {}
411 Gen_fpage(l4_fpage_t const &fp, l4_addr_t snd_base = 0,
412 Map_type map_type = Map,
413 Cacheopt cache = None, Continue cont = Last)
414 : T(L4_ITEM_MAP | (snd_base & (~0UL << 10)) | l4_umword_t(map_type) | l4_umword_t(cache)
419 Gen_fpage(L4::Cap<void> cap, unsigned rights)
420 : T(L4_ITEM_MAP | Map | (rights & 0xf0), cap.fpage(rights).raw)
423 static Gen_fpage<T> obj(l4_addr_t base, int order,
424 unsigned char rights,
425 l4_addr_t snd_base = 0,
426 Map_type map_type = Map,
427 Continue cont = Last)
428 { return Gen_fpage<T>(Obj, base << 12, order, rights, snd_base, map_type, None, cont); }
430 static Gen_fpage<T> mem(l4_addr_t base, int order,
431 unsigned char rights,
432 l4_addr_t snd_base = 0,
433 Map_type map_type = Map,
434 Cacheopt cache = None, Continue cont = Last)
436 return Gen_fpage<T>(Memory, base, order, rights, snd_base,
437 map_type, cache, cont);
440 static Gen_fpage<T> io(l4_addr_t base, int order,
441 unsigned char rights,
442 l4_addr_t snd_base = 0,
443 Map_type map_type = Map,
444 Continue cont = Last)
445 { return Gen_fpage<T>(Io, base << 12, order, rights, snd_base, map_type, None, cont); }
447 unsigned order() const { return (T::_data >> 6) & 0x3f; }
448 unsigned snd_order() const { return (T::_data >> 6) & 0x3f; }
449 unsigned rcv_order() const { return (T::_base >> 6) & 0x3f; }
450 l4_addr_t base() const { return T::_data & (~0UL << 12); }
451 l4_addr_t snd_base() const { return T::_base & (~0UL << 10); }
452 void snd_base(l4_addr_t b) { T::_base = (T::_base & ~(~0UL << 10)) | (b & (~0UL << 10)); }
454 bool is_valid() const { return T::_base & L4_ITEM_MAP; }
455 // A cap has been mapped
456 bool cap_received() const { return (T::_base & 0x3e) == 0x38; }
457 // the label out of an IPC gate has been received, L4_RCV_ITEM_LOCAL_ID
458 // must be specified, and the IPC gate must be local to the receiver
459 // (i.e., the target thread of the IPC gate is in the same task as the
461 bool id_received() const { return (T::_base & 0x3e) == 0x3c; }
462 // Sender and receiver are in the same task, set only iff
463 // L4_RCV_ITEM_LOCAL_ID has been specified by the receiver, the value
464 // delivered is the cap-index (in the task)
465 bool local_id_received() const { return (T::_base & 0x3e) == 0x3e; }
466 l4_umword_t data() const { return T::_data; }
467 l4_umword_t base_x() const { return T::_base; }
471 typedef Gen_fpage<Snd_item> Snd_fpage;
472 typedef Gen_fpage<Buf_item> Rcv_fpage;
474 #ifdef L4_CXX_IPC_SUPPORT_STRINGS
475 template <typename T, typename B>
476 class Gen_string : public T
479 Gen_string() : T(0, 0) {}
480 Gen_string(B buf, unsigned long size)
481 : T(size << 10, l4_umword_t(buf))
484 unsigned long len() const { return T::_base >> 10; }
487 typedef Gen_string<Snd_item, void const *> Snd_string;
488 typedef Gen_string<Buf_item, void *> Rcv_string;
492 template< typename T, template <typename X> class B > struct Generic_va_type : public B<T>
494 enum { Id = B<T>::Id };
496 typedef T const &Ret_value;
499 static Ret_value value(void const *d)
500 { return *reinterpret_cast<Value const *>(d); }
502 static void const *addr_of(Value const &v) { return &v; }
504 static unsigned size(void const *) { return sizeof(T); }
506 static L4_varg_type unsigned_id() { return (L4_varg_type)(Id & ~L4_VARG_TYPE_SIGN); }
507 static L4_varg_type signed_id() { return (L4_varg_type)(Id | L4_VARG_TYPE_SIGN); }
508 static L4_varg_type id() { return (L4_varg_type)Id; }
511 template< typename T > struct Va_type_id;
512 template<> struct Va_type_id<l4_umword_t> { enum { Id = L4_VARG_TYPE_UMWORD }; };
513 template<> struct Va_type_id<l4_mword_t> { enum { Id = L4_VARG_TYPE_MWORD }; };
514 template<> struct Va_type_id<l4_fpage_t> { enum { Id = L4_VARG_TYPE_FPAGE }; };
515 template<> struct Va_type_id<void> { enum { Id = L4_VARG_TYPE_NIL }; };
516 template<> struct Va_type_id<char const *> { enum { Id = L4_VARG_TYPE_STRING }; };
518 template< typename T > struct Va_type;
520 template<> struct Va_type<l4_umword_t> : public Generic_va_type<l4_umword_t, Va_type_id> {};
521 template<> struct Va_type<l4_mword_t> : public Generic_va_type<l4_mword_t, Va_type_id> {};
522 template<> struct Va_type<l4_fpage_t> : public Generic_va_type<l4_fpage_t, Va_type_id> {};
524 template<> struct Va_type<void>
526 typedef void Ret_value;
529 static void const *addr_of(void) { return 0; }
531 static void value(void const *) {}
532 static L4_varg_type id() { return L4_VARG_TYPE_NIL; }
533 static unsigned size(void const *) { return 0; }
536 template<> struct Va_type<char const *>
538 typedef char const *Ret_value;
539 typedef char const *Value;
541 static void const *addr_of(Value v) { return v; }
543 static L4_varg_type id() { return L4_VARG_TYPE_STRING; }
544 static unsigned size(void const *s)
546 char const *_s = reinterpret_cast<char const *>(s);
555 static Ret_value value(void const *d) { return (char const *)d; }
567 typedef l4_umword_t Tag;
569 L4_varg_type type() const { return (L4_varg_type)(_tag & 0xff); }
570 int length() const { return _tag >> 16; }
572 void tag(Tag tag) { _tag = tag; }
573 Tag tag() const { return _tag; }
574 void data(char const *d) { _d = d; }
576 char const *data() const { return _d; }
577 char const *&data() { return _d; }
579 Varg() : _tag(0), _d(0) {}
581 Varg(L4_varg_type t, void const *v, int len)
582 : _tag(t | ((l4_mword_t)len << 16)), _d((char const *)v)
585 template< typename V >
586 typename Va_type<V>::Ret_value value() const
587 { return Va_type<V>::value(_d); }
590 template< typename T >
591 bool is_of() const { return Va_type<T>::id() == type(); }
593 bool is_nil() const { return is_of<void>(); }
595 bool is_of_int() const
596 { return (type() & ~L4_VARG_TYPE_SIGN) == L4_VARG_TYPE_UMWORD; }
598 template< typename T >
599 bool get_value(typename Va_type<T>::Value *v) const
604 *v = Va_type<T>::value(_d);
608 template< typename T >
609 void set_value(void const *d)
611 typedef Va_type<T> Vt;
612 _tag = Vt::id() | (Vt::size(d) << 16);
613 _d = (char const *)d;
619 class Varg_t : public Varg
622 typedef typename Va_type<T>::Value Value;
623 explicit Varg_t(Value v) : Varg()
624 { _data = v; set_value<T>(Va_type<T>::addr_of(_data)); }
630 namespace Utcb_stream_check
632 static bool check_utcb_data_offset(unsigned sz)
633 { return sz > sizeof(l4_umword_t) * L4_UTCB_GENERIC_DATA_SIZE; }
638 * \brief Input stream for IPC unmarshalling.
641 * Ipc::Istream is part of the dynamic IPC marshalling infrastructure, as well
642 * as Ipc::Ostream and Ipc::Iostream.
644 * Ipc::Istream is an input stream supporting extraction of values from an
645 * IPC message buffer. A received IPC message can be unmarshalled using the
646 * usual extraction operator (>>).
648 * There exist some special wrapper classes to extract arrays (see
649 * Ipc_buf_cp_in and Ipc_buf_in) and indirect strings (see Msg_in_buffer and
656 * \brief Create an input stream for the given message buffer.
658 * The given message buffer is used for IPC operations wait()/receive()
659 * and received data can be extracted using the >> operator afterwards.
660 * In the case of indirect message parts a buffer of type Msg_in_buffer
661 * must be inserted into the stream before the IPC operation and contains
662 * received data afterwards.
664 * \param msg The message buffer to receive IPC messages.
666 Istream(l4_utcb_t *utcb)
667 : _tag(), _utcb(utcb),
668 _current_msg(reinterpret_cast<char*>(l4_utcb_mr_u(utcb)->mr)),
669 _pos(0), _current_buf(0)
673 * \brief Reset the stream to empty, and ready for receive()/wait().
674 * The stream is reset to the same state as on its creation.
680 _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
684 * \brief Check whether a value of type T can be obtained from the stream.
686 template< typename T >
689 unsigned apos = cxx::Type_traits<T>::align(_pos);
690 return apos + sizeof(T) <= _tag.words() * sizeof(l4_umword_t);
694 * \name Get/Put Functions.
695 * These functions are basically used to implement the extraction operators
696 * (>>) and should not be called directly.
698 * See \link ipc_stream IPC stream operators \endlink.
703 * \brief Copy out an array of type \a T with \a size elements.
705 * \param buf Pointer to a buffer for size elements of type T.
706 * \param size number of elements of type T to copy out.
708 * See \link ipc_stream IPC stream operators \endlink.
710 template< typename T >
711 unsigned long get(T *buf, unsigned long elems)
713 unsigned long size = elems * sizeof(T);
714 _pos = cxx::Type_traits<T>::align(_pos);
715 if (Utcb_stream_check::check_utcb_data_offset(_pos + size))
718 __builtin_memcpy(buf, _current_msg + _pos, size);
725 * \brief Skip size elements of type T in the stream.
726 * \param size number of elements to skip.
728 template< typename T >
729 void skip(unsigned long size)
732 _pos = cxx::Type_traits<T>::align(_pos);
733 if (Utcb_stream_check::check_utcb_data_offset(_pos + size))
739 * \brief Read one size elements of type T from the stream and return
742 * In contrast to a normal get, this version does actually not copy the data
743 * but returns a pointer to the data.
745 * \param buf a Msg_ptr that is actually set to point to the element in the
747 * \param elems number of elements to extract (default is 1).
749 * See \link ipc_stream IPC stream operators \endlink.
751 template< typename T >
752 unsigned long get(Msg_ptr<T> const &buf, unsigned long elems = 1)
754 unsigned long size = elems * sizeof(T);
755 _pos = cxx::Type_traits<T>::align(_pos);
756 if (Utcb_stream_check::check_utcb_data_offset(_pos + size))
759 buf.set(reinterpret_cast<T*>(_current_msg + _pos));
766 * \brief Extract a single element of type T from the stream.
767 * \param v Output: the element.
769 * See \link ipc_stream IPC stream operators \endlink.
771 template< typename T >
774 _pos = cxx::Type_traits<T>::align(_pos);
775 if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
780 v = *(reinterpret_cast<T*>(_current_msg + _pos));
785 bool get(Ipc::Varg *va)
788 if (!has_more<Ipc::Varg::Tag>())
795 get(msg_ptr(va->data()), va->length());
801 * \brief Get the message tag of a received IPC.
802 * \return The L4 message tag for the received IPC.
804 * This is in particular useful for handling page faults or exceptions.
806 * See \link ipc_stream IPC stream operators \endlink.
808 l4_msgtag_t tag() const { return _tag; }
812 * \brief Get the message tag of a received IPC.
813 * \return A reference to the L4 message tag for the received IPC.
815 * This is in particular useful for handling page faults or exceptions.
817 * See \link ipc_stream IPC stream operators \endlink.
819 l4_msgtag_t &tag() { return _tag; }
825 * \brief Put a receive item into the stream's buffer registers.
827 inline bool put(Buf_item const &);
831 * \brief Put a small receive item into the stream's buffer registers.
833 inline bool put(Small_buf const &);
837 * \name IPC operations.
842 * \brief Wait for an incoming message from any sender.
843 * \param src contains the sender after a successful IPC operation.
844 * \return The IPC result dope (l4_msgtag_t).
846 * This wait is actually known as 'open wait'.
848 inline l4_msgtag_t wait(l4_umword_t *src)
849 { return wait(src, L4_IPC_NEVER); }
852 * \brief Wait for an incoming message from any sender.
853 * \param src contains the sender after a successful IPC operation.
854 * \param timeout Timeout used for IPC.
855 * \return The IPC result dope (l4_msgtag_t).
857 * This wait is actually known as 'open wait'.
859 inline l4_msgtag_t wait(l4_umword_t *src, l4_timeout_t timeout);
862 * \brief Wait for a message from the specified sender.
863 * \param src The sender id to receive from.
864 * \return The IPC result dope (l4_msgtag_t).
866 * This is commonly known as 'closed wait'.
868 inline l4_msgtag_t receive(l4_cap_idx_t src)
869 { return receive(src, L4_IPC_NEVER); }
870 inline l4_msgtag_t receive(l4_cap_idx_t src, l4_timeout_t timeout);
875 * \brief Return utcb pointer.
877 inline l4_utcb_t *utcb() const { return _utcb; }
884 unsigned char _current_buf;
887 class Istream_copy : public Istream
893 Istream_copy(Istream const &o) : Istream(o), _mrs(*l4_utcb_mr_u(o.utcb()))
895 // do some reverse mr to utcb trickery
896 _utcb = (l4_utcb_t*)((l4_addr_t)&_mrs - (l4_addr_t)l4_utcb_mr_u((l4_utcb_t*)0));
897 _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
903 * \brief Read a value out of a stream.
905 * \param s An Istream.
906 * \return The value of type T.
908 * The stream position is progressed accordingly.
910 template< typename T >
912 T read(Istream &s) { T t; s >> t; return t; }
915 * \brief Output stream for IPC marshalling.
918 * Ipc::Ostream is part of the dynamic IPC marshalling infrastructure, as well
919 * as Ipc::Istream and Ipc::Iostream.
921 * Ipc::Ostream is an output stream supporting insertion of values into an
922 * IPC message buffer. A IPC message can be marshalled using the
923 * usual insertion operator <<, see \link ipc_stream IPC stream operators
926 * There exist some special wrapper classes to insert arrays (see
927 * Ipc::Buf_cp_out) and indirect strings (see Msg_out_buffer and
933 * \brief Create an IPC output stream using the given message buffer \a msg.
935 Ostream(l4_utcb_t *utcb)
936 : _tag(), _utcb(utcb),
937 _current_msg(reinterpret_cast<char *>(l4_utcb_mr_u(_utcb)->mr)),
938 _pos(0), _current_item(0)
942 * \brief Reset the stream to empty, same state as a newly created stream.
948 _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
952 * \name Get/Put functions.
954 * These functions are basically used to implement the insertion operators
955 * (<<) and should not be called directly.
957 * See \link ipc_stream IPC stream operators \endlink.
962 * \brief Put an array with \a size elements of type \a T into the stream.
963 * \param buf A pointer to the array to insert into the buffer.
964 * \param size The number of elements in the array.
966 template< typename T >
967 bool put(T *buf, unsigned long size)
970 _pos = cxx::Type_traits<T>::align(_pos);
971 if (Utcb_stream_check::check_utcb_data_offset(_pos + size))
974 __builtin_memcpy(_current_msg + _pos, buf, size);
980 * \brief Insert an element of type \a T into the stream.
981 * \param v The element to insert.
983 template< typename T >
986 _pos = cxx::Type_traits<T>::align(_pos);
987 if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
990 *(reinterpret_cast<T*>(_current_msg + _pos)) = v;
995 int put(Varg const &va)
998 put(va.data(), va.length());
1003 template< typename T >
1004 int put(Varg_t<T> const &va)
1005 { return put(static_cast<Varg const &>(va)); }
1008 * \brief Extract the L4 message tag from the stream.
1009 * \return the extracted L4 message tag.
1011 l4_msgtag_t tag() const { return _tag; }
1014 * \brief Extract a reference to the L4 message tag from the stream.
1015 * \return A reference to the L4 message tag.
1017 l4_msgtag_t &tag() { return _tag; }
1023 * \brief Put a send item into the stream's message buffer.
1025 inline bool put_snd_item(Snd_item const &);
1029 * \name IPC operations.
1034 * \brief Send the message via IPC to the given receiver.
1035 * \param dst The destination for the message.
1037 inline l4_msgtag_t send(l4_cap_idx_t dst, long proto = 0, unsigned flags = 0);
1042 * \brief Return utcb pointer.
1044 inline l4_utcb_t *utcb() const { return _utcb; }
1047 * \brief Get the currently used bytes in the stream.
1049 unsigned long tell() const
1051 register unsigned w = (_pos + sizeof(l4_umword_t)-1) / sizeof(l4_umword_t);
1052 w -= _current_item * 2;
1053 _tag = l4_msgtag(0, w, _current_item, 0);
1057 l4_msgtag_t prepare_ipc(long proto = 0, unsigned flags = 0)
1059 register unsigned w = (_pos + sizeof(l4_umword_t)-1) / sizeof(l4_umword_t);
1060 w -= _current_item * 2;
1061 return l4_msgtag(proto, w, _current_item, flags);
1069 unsigned char _current_item;
1074 * \brief Input/Output stream for IPC [un]marshalling.
1077 * The Ipc::Iostream is part of the AW Env IPC framework as well as
1078 * Ipc::Istream and Ipc::Ostream.
1079 * In particular an Ipc::Iostream is a combination of an Ipc::Istream and an
1080 * Ipc::Ostream. It can use either a single message buffer for receiving and
1081 * sending messages or a pair of a receive and a send buffer. The stream also
1082 * supports combined IPC operations such as call() and reply_and_wait(), which
1083 * can be used to implement RPC functionality.
1085 class Iostream : public Istream, public Ostream
1090 * \brief Create an IPC IO stream with a single message buffer.
1091 * \param msg The message buffer used as backing store.
1093 * The created IO stream uses the same message buffer for sending and
1094 * receiving IPC messages.
1096 explicit Iostream(l4_utcb_t *utcb)
1097 : Istream(utcb), Ostream(utcb)
1102 * \brief Reset the stream to its initial state.
1104 * Input as well as the output stream are reset.
1114 * \name Get/Put functions.
1116 * These functions are basically used to implement the insertion operators
1117 * (<<) and should not be called directly.
1119 * See \link ipc_stream IPC stream operators \endlink.
1130 * \name IPC operations.
1135 * \brief Do an IPC call using the message in the output stream and
1136 * receiving to the input stream.
1137 * \param dst The destination L4 UID (thread) to call.
1138 * \param timeout The IPC timeout for the call.
1139 * \param proto The protocol value to use in the message tag.
1140 * \return the result dope of the IPC operation.
1142 * This is a combined IPC operation consisting of a send and a receive
1143 * to/from the given destination \a dst.
1145 * A call is usually used by clients for RPCs to a server.
1148 inline l4_msgtag_t call(l4_cap_idx_t dst, l4_timeout_t timeout, long proto = 0);
1149 inline l4_msgtag_t call(l4_cap_idx_t dst, long proto = 0);
1152 * \brief Do an IPC reply and wait.
1153 * \param src_dst Input: the destination for the send operation. <br>
1154 * Output: the source of the received message.
1155 * \return the result dope of the IPC operation.
1157 * This is a combined IPC operation consisting of a send operation and
1158 * an open wait for any message.
1160 * A reply and wait is usually used by servers that reply to a client
1161 * and wait for the next request by any other client.
1163 inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst, long proto = 0)
1164 { return reply_and_wait(src_dst, L4_IPC_SEND_TIMEOUT_0, proto); }
1166 inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
1168 { return send_and_wait(dest, src, L4_IPC_SEND_TIMEOUT_0, proto); }
1171 * \brief Do an IPC reply and wait.
1172 * \param src_dst Input: the destination for the send operation. <br>
1173 * Output: the source of the received message.
1174 * \param timeout Timeout used for IPC.
1175 * \return the result dope of the IPC operation.
1177 * This is a combined IPC operation consisting of a send operation and
1178 * an open wait for any message.
1180 * A reply and wait is usually used by servers that reply to a client
1181 * and wait for the next request by any other client.
1183 inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst,
1184 l4_timeout_t timeout, long proto = 0);
1185 inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
1186 l4_timeout_t timeout, long proto = 0);
1187 inline l4_msgtag_t reply(l4_timeout_t timeout, long proto = 0);
1188 inline l4_msgtag_t reply(long proto = 0)
1189 { return reply(L4_IPC_SEND_TIMEOUT_0, proto); }
1196 Ostream::put_snd_item(Snd_item const &v)
1199 _pos = cxx::Type_traits<Snd_item>::align(_pos);
1200 if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
1203 *(reinterpret_cast<T*>(_current_msg + _pos)) = v;
1211 Istream::put(Buf_item const &item)
1213 if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 3)
1216 l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK;
1218 reinterpret_cast<Buf_item&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item;
1225 Istream::put(Small_buf const &item)
1227 if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 2)
1230 l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK;
1232 reinterpret_cast<Small_buf&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item;
1239 Ostream::send(l4_cap_idx_t dst, long proto, unsigned flags)
1241 l4_msgtag_t tag = prepare_ipc(proto, L4_MSGTAG_FLAGS & flags);
1242 return l4_ipc_send(dst, _utcb, tag, L4_IPC_NEVER);
1246 Iostream::call(l4_cap_idx_t dst, l4_timeout_t timeout, long label)
1248 l4_msgtag_t tag = prepare_ipc(label);
1249 tag = l4_ipc_call(dst, Ostream::_utcb, tag, timeout);
1250 Istream::tag() = tag;
1256 Iostream::call(l4_cap_idx_t dst, long label)
1257 { return call(dst, L4_IPC_NEVER, label); }
1261 Iostream::reply_and_wait(l4_umword_t *src_dst, l4_timeout_t timeout, long proto)
1263 l4_msgtag_t tag = prepare_ipc(proto);
1264 tag = l4_ipc_reply_and_wait(Ostream::_utcb, tag, src_dst, timeout);
1265 Istream::tag() = tag;
1272 Iostream::send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
1273 l4_timeout_t timeout, long proto)
1275 l4_msgtag_t tag = prepare_ipc(proto);
1276 tag = l4_ipc_send_and_wait(dest, Ostream::_utcb, tag, src, timeout);
1277 Istream::tag() = tag;
1283 Iostream::reply(l4_timeout_t timeout, long proto)
1285 l4_msgtag_t tag = prepare_ipc(proto);
1286 tag = l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, Ostream::_utcb, tag, timeout);
1287 Istream::tag() = tag;
1293 Istream::wait(l4_umword_t *src, l4_timeout_t timeout)
1296 res = l4_ipc_wait(_utcb, src, timeout);
1304 Istream::receive(l4_cap_idx_t src, l4_timeout_t timeout)
1307 res = l4_ipc_receive(src, _utcb, timeout);
1317 * \brief Extract one element of type \a T from the stream \a s.
1318 * \ingroup ipc_stream
1319 * \param s The stream to extract from.
1320 * \param v Output: extracted value.
1321 * \return the stream \a s.
1323 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, bool &v) { s.get(v); return s; }
1324 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, int &v) { s.get(v); return s; }
1325 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long int &v) { s.get(v); return s; }
1326 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long long int &v) { s.get(v); return s; }
1327 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned int &v) { s.get(v); return s; }
1328 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long int &v) { s.get(v); return s; }
1329 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long long int &v) { s.get(v); return s; }
1330 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, short int &v) { s.get(v); return s; }
1331 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned short int &v) { s.get(v); return s; }
1332 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, char &v) { s.get(v); return s; }
1333 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned char &v) { s.get(v); return s; }
1334 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, signed char &v) { s.get(v); return s; }
1335 inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Buf_item const &v) { s.put(v); return s; }
1336 inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Small_buf const &v) { s.put(v); return s; }
1337 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Snd_item &v)
1341 v = L4::Ipc::Snd_item(b, d);
1344 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Varg &v)
1345 { s.get(&v); return s; }
1349 * \brief Extract the L4 message tag from the stream \a s.
1350 * \ingroup ipc_stream
1351 * \param s The stream to extract from.
1352 * \param v Output: the extracted tag.
1353 * \return the stream \a s.
1356 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, l4_msgtag_t &v)
1363 * \brief Extract an array of \a T elements from the stream \a s.
1364 * \ingroup ipc_stream
1366 * This operator actually does not copy out the data in the array, but
1367 * returns a pointer into the message buffer itself. This means that the
1368 * data is only valid as long as there is no new data inserted into the stream.
1370 * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
1372 * \param s The stream to extract from.
1373 * \param v Output: pointer to the extracted array (ipc_buf_in()).
1374 * \return the stream \a s.
1376 template< typename T >
1378 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1379 L4::Ipc::Internal::Buf_in<T> const &v)
1383 v.set_size(s.get(L4::Ipc::Msg_ptr<T>(v.buf()), si));
1388 * \brief Extract an element of type \a T from the stream \a s.
1389 * \ingroup ipc_stream
1391 * This operator actually does not copy out the data, but
1392 * returns a pointer into the message buffer itself. This means that the
1393 * data is only valid as long as there is no new data inserted into the stream.
1397 * \param s The stream to extract from.
1398 * \param v Output: pointer to the extracted element.
1399 * \return the stream \a s.
1401 template< typename T >
1403 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1404 L4::Ipc::Msg_ptr<T> const &v)
1411 * \brief Extract an array of \a T elements from the stream \a s.
1412 * \ingroup ipc_stream
1414 * This operator does a copy out of the data into the given buffer.
1416 * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
1418 * \param s The stream to extract from.
1419 * \param v buffer description to copy the array to (Ipc::Buf_cp_out()).
1420 * \return the stream \a s.
1422 template< typename T >
1424 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1425 L4::Ipc::Internal::Buf_cp_in<T> const &v)
1429 v.size() = s.get(v.buf(), cxx::min(v.size(), sz));
1434 * \brief Extract a zero-terminated string from the stream.
1435 * \ingroup ipc_stream
1437 * This operator does a copy out of the data into the given buffer.
1439 * \param s The stream to extract from.
1440 * \param v buffer description to copy the array to (Ipc::Str_cp_out()).
1441 * \return the stream \a s.
1443 template< typename T >
1445 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1446 L4::Ipc::Str_cp_in<T> const &v)
1450 unsigned long rsz = s.get(v.buf(), cxx::min(v.size(), sz));
1451 if (rsz < v.size() && v.buf()[rsz - 1])
1452 ++rsz; // add the zero termination behind the received data
1455 v.buf()[rsz - 1] = 0;
1463 * \brief Insert an element to type \a T into the stream \a s.
1464 * \ingroup ipc_stream
1466 * \param s The stream to insert the element \a v.
1467 * \param v The element to insert.
1468 * \return the stream \a s.
1470 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, bool v) { s.put(v); return s; }
1471 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, int v) { s.put(v); return s; }
1472 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long int v) { s.put(v); return s; }
1473 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long long int v) { s.put(v); return s; }
1474 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned int v) { s.put(v); return s; }
1475 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long int v) { s.put(v); return s; }
1476 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long long int v) { s.put(v); return s; }
1477 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, short int v) { s.put(v); return s; }
1478 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned short int v) { s.put(v); return s; }
1479 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char v) { s.put(v); return s; }
1480 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned char v) { s.put(v); return s; }
1481 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, signed char v) { s.put(v); return s; }
1482 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Snd_item const &v) { s.put_snd_item(v); return s; }
1483 template< typename T >
1484 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Cap<T> const &v)
1485 { s << L4::Ipc::Snd_fpage(v.fpage()); return s; }
1487 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg const &v)
1488 { s.put(v); return s; }
1489 template< typename T >
1490 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg_t<T> const &v)
1491 { s.put(v); return s; }
1494 * \brief Insert the L4 message tag into the stream \a s.
1495 * \ingroup ipc_stream
1497 * \note Only one message tag can be inserted into a stream. Multiple
1498 * insertions simply overwrite previous insertions.
1499 * \param s The stream to insert the tag \a v.
1500 * \param v The L4 message tag to insert.
1501 * \return the stream \a s.
1504 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, l4_msgtag_t const &v)
1511 * \brief Insert an array with elements of type \a T into the stream \a s.
1512 * \ingroup ipc_stream
1514 * \param s The stream to insert the array \a v.
1515 * \param v The array to insert (see Ipc::Buf_cp_out()).
1516 * \return the stream \a s.
1518 template< typename T >
1520 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s,
1521 L4::Ipc::Internal::Buf_cp_out<T> const &v)
1524 s.put(v.buf(), v.size());
1529 * \brief Insert a zero terminated character string into the stream \a s.
1530 * \ingroup ipc_stream
1532 * \param s The stream to insert the string \a v.
1533 * \param v The string to insert.
1534 * \return the stream \a s.
1536 * This operator produces basically the same content as the array insertion,
1537 * however the length of the array is calculated using <c> strlen(\a v) + 1
1538 * </c>. The string is copied into the message including the trailing zero.
1541 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char const *v)
1543 unsigned long l = __builtin_strlen(v) + 1;
1550 #ifdef L4_CXX_IPC_BACKWARD_COMPAT
1554 template< typename T > class Ipc_buf_cp_out : public Ipc::Buf_cp_out<T> {};
1555 template< typename T > class Ipc_buf_cp_in : public Ipc::Buf_cp_in<T> {};
1556 template< typename T > class Ipc_buf_in : public Ipc::Buf_in<T> {};
1557 template< typename T > class Msg_ptr : public Ipc::Msg_ptr<T> {};
1560 template< typename T >
1561 Ipc::Internal::Buf_cp_out<T> ipc_buf_cp_out(T *v, unsigned long size)
1562 L4_DEPRECATED("Use L4::Ipc::buf_cp_out() now");
1564 template< typename T >
1565 Ipc::Internal::Buf_cp_out<T> ipc_buf_cp_out(T *v, unsigned long size)
1566 { return Ipc::Internal::Buf_cp_out<T>(v, size); }
1569 template< typename T >
1570 Ipc::Internal::Buf_cp_in<T> ipc_buf_cp_in(T *v, unsigned long &size)
1571 L4_DEPRECATED("Use L4::Ipc::buf_cp_in() now");
1573 template< typename T >
1574 Ipc::Internal::Buf_cp_in<T> ipc_buf_cp_in(T *v, unsigned long &size)
1575 { return Ipc::Internal::Buf_cp_in<T>(v, size); }
1578 template< typename T >
1579 Ipc::Internal::Buf_in<T> ipc_buf_in(T *&v, unsigned long &size)
1580 L4_DEPRECATED("Use L4::Ipc::buf_in() now");
1582 template< typename T >
1583 Ipc::Internal::Buf_in<T> ipc_buf_in(T *&v, unsigned long &size)
1584 { return Ipc::Internal::Buf_in<T>(v, size); }
1587 template< typename T >
1588 Ipc::Msg_ptr<T> msg_ptr(T *&p)
1589 L4_DEPRECATED("Use L4::Ipc::msg_ptr() now");
1591 template< typename T >
1592 Ipc::Msg_ptr<T> msg_ptr(T *&p)
1593 { return Ipc::Msg_ptr<T>(p); }
1595 typedef Ipc::Istream Ipc_istream L4_DEPRECATED("Use L4::Ipc::Istream now");
1596 typedef Ipc::Ostream Ipc_ostream L4_DEPRECATED("Use L4::Ipc::Ostream now");;
1597 typedef Ipc::Iostream Ipc_iostream L4_DEPRECATED("Use L4::Ipc::Iostream now");;
1598 typedef Ipc::Snd_fpage Snd_fpage L4_DEPRECATED("Use L4::Ipc::Snd_fpage now");;
1599 typedef Ipc::Rcv_fpage Rcv_fpage L4_DEPRECATED("Use L4::Ipc::Rcv_fpage now");;
1600 typedef Ipc::Small_buf Small_buf L4_DEPRECATED("Use L4::Ipc::Small_buf now");;
1604 template< typename T > class Buf_cp_in : public Internal::Buf_cp_in<T>
1607 Buf_cp_in(T *v, unsigned long &size) : Internal::Buf_cp_in<T>(v, size) {}
1610 template< typename T >
1611 class Buf_cp_out : public Internal::Buf_cp_out<T>
1614 Buf_cp_out(T const *v, unsigned long size) : Internal::Buf_cp_out<T>(v, size) {}
1617 template< typename T >
1618 class Buf_in : public Internal::Buf_in<T>
1621 Buf_in(T *&v, unsigned long &size) : Internal::Buf_in<T>(v, size) {}
1626 template< typename T >
1628 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_cp_in<T> const &v)
1629 L4_DEPRECATED("Use L4::Ipc::buf_cp_in() now");
1631 template< typename T >
1633 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_cp_in<T> const &v)
1634 { return operator>>(s, static_cast<L4::Ipc::Internal::Buf_cp_in<T> >(v)); }
1636 template< typename T >
1638 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_in<T> const &v)
1639 L4_DEPRECATED("Use L4::Ipc::buf_in() now");
1641 template< typename T >
1643 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_in<T> const &v)
1644 { return operator>>(s, static_cast<L4::Ipc::Internal::Buf_in<T> >(v)); }
1646 template< typename T >
1648 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Buf_cp_out<T> const &v)
1649 L4_DEPRECATED("Use L4::Ipc::buf_cp_out() now");
1651 template< typename T >
1653 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Buf_cp_out<T> const &v)
1654 { return operator<<(s, static_cast<L4::Ipc::Internal::Buf_cp_out<T> >(v)); }