1 /**
2  * \file
3  * Common IPC interface.
4  * \ingroup l4_api
5  */
6 /*
7  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
9  *               Björn Döbel <doebel@os.inf.tu-dresden.de>,
10  *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
11  *     economic rights: Technische Universität Dresden (Germany)
12  *
13  * This file is part of TUD:OS and distributed under the terms of the
14  * GNU General Public License 2.
15  * Please see the COPYING-GPL-2 file for details.
16  *
17  * As a special exception, you may use this file as part of a free software
18  * library without restriction.  Specifically, if other files instantiate
19  * templates or use macros or inline functions from this file, or you compile
20  * this file and link it with other files to produce an executable, this
21  * file does not by itself cause the resulting executable to be covered by
22  * the GNU General Public License.  This exception does not however
23  * invalidate any other reasons why the executable file might be covered by
24  * the GNU General Public License.
25  */
26 #ifndef __L4SYS__INCLUDE__L4API_FIASCO__IPC_H__
27 #define __L4SYS__INCLUDE__L4API_FIASCO__IPC_H__
28 
29 #include <l4/sys/types.h>
30 #include <l4/sys/utcb.h>
31 #include <l4/sys/err.h>
32 
33 /**
34  * \defgroup l4_ipc_api Object Invocation
35  * \ingroup l4_api
36  * API for L4 object invocation.
37  *
38  * \includefile{l4/sys/ipc.h}
39  *
40  * General abstractions for L4 object invocation. The basic principle is that
41  * all objects are denoted by a capability that is accessed via a capability
42  * selector (see \link l4_cap_api Capabilities \endlink).
43  *
44  * This set of functions is common to all kinds of objects provided by the
45  * L4 micro kernel. The concrete semantics of an invocation depends on the
46  * object that shall be invoked.
47  *
48  * Objects may be invoked in various ways, the most common way is to use
49  * a *call* operation (l4_ipc_call()). However, there are a lot more
50  * flavours available that have a semantics depending on the object.
51  *
52  * \see \ref l4_kernel_object_gate_api
53  *
54  */
55 
56 /*****************************************************************************
57  *** IPC result checking
58  *****************************************************************************/
59 
60 /**
61  * \defgroup l4_ipc_err_api Error Handling
62  * \ingroup l4_ipc_api
63  * Error handling for L4 object invocation.
64  *
65  * \includefile{l4/sys/ipc.h}
66  */
67 
68 /**
69  * Error codes in the *error* TCR.
70  * \ingroup l4_ipc_err_api
71  *
72  * The error codes are accessible via the *error* TCR, see
73  * #l4_thread_regs_t.error.
74  */
75 enum l4_ipc_tcr_error_t
76 {
77   L4_IPC_ERROR_MASK       = 0x1F, /**< Mask for error bits. */
78   L4_IPC_SND_ERR_MASK     = 0x01, /**< Send error mask. */
79 
80   L4_IPC_ENOT_EXISTENT    = 0x04, /**< Non-existing destination or source.
81                                    **  \ingroup l4_ipc_api
82                                    **/
83   L4_IPC_RETIMEOUT        = 0x03, /**< Timeout during receive operation.
84                                    **  \ingroup l4_ipc_api
85                                    **/
86   L4_IPC_SETIMEOUT        = 0x02, /**< Timeout during send operation.
87                                    **  \ingroup l4_ipc_api
88                                    **/
89   L4_IPC_RECANCELED       = 0x07, /**< Receive operation canceled.
90                                    **  \ingroup l4_ipc_api
91                                    **/
92   L4_IPC_SECANCELED       = 0x06, /**< Send operation canceled.
93                                    **  \ingroup l4_ipc_api
94                                    **/
95   L4_IPC_REMAPFAILED      = 0x11, /**< Map flexpage failed in receive
96                                    **  operation.
97                                    **  \ingroup l4_ipc_api
98                                    **/
99   L4_IPC_SEMAPFAILED      = 0x10, /**< Map flexpage failed in send operation.
100                                    **  \ingroup l4_ipc_api
101                                    **/
102   L4_IPC_RESNDPFTO        = 0x0b, /**< Send-pagefault timeout in receive
103                                    **  operation.
104                                    **  \ingroup l4_ipc_api
105                                    **/
106   L4_IPC_SESNDPFTO        = 0x0a, /**< Send-pagefault timeout in send
107                                    **  operation.
108                                    **  \ingroup l4_ipc_api
109                                    **/
110   L4_IPC_RERCVPFTO        = 0x0d, /**< Receive-pagefault timeout in receive
111                                    **  operation.
112                                    **  \ingroup l4_ipc_api
113                                    **/
114   L4_IPC_SERCVPFTO        = 0x0c, /**< Receive-pagefault timeout in send
115                                    **  operation.
116                                    **  \ingroup l4_ipc_api
117                                    **/
118   L4_IPC_REABORTED        = 0x0f, /**< Receive operation aborted.
119                                    **  \ingroup l4_ipc_api
120                                    **/
121   L4_IPC_SEABORTED        = 0x0e, /**< Send operation aborted.
122                                    **  \ingroup l4_ipc_api
123                                    **/
124   L4_IPC_REMSGCUT         = 0x09, /**< Cut receive message, due to
125                                    **  message buffer is too small.
126                                    **  \ingroup l4_ipc_api
127                                    **/
128   L4_IPC_SEMSGCUT         = 0x08, /**< Cut send message. due to
129                                    **  message buffer is too small,
130                                    **  \ingroup l4_ipc_api
131                                    **/
132 };
133 
134 
135 /**
136  * Get the error code for an object invocation.
137  * \ingroup l4_ipc_err_api
138  *
139  * \param tag   Return value of the invocation.
140  * \param utcb  UTCB that was used for the invocation.
141  *
142  * \return 0 if no error condition is set,
143  *         error code otherwise (see #l4_ipc_tcr_error_t).
144  */
145 L4_INLINE l4_umword_t
146 l4_ipc_error(l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW;
147 
148 
149 /**
150  * Return error code of a system call return message tag or the tag label.
151  * \ingroup l4_ipc_err_api
152  *
153  * \param tag  System call return message type.
154  *
155  * \return  In case of IPC error a negative error code in the range of
156  *          L4_EIPC_LO to L4_EIPC_HI, otherwise the tag label.
157  */
158 L4_INLINE long
159 l4_error(l4_msgtag_t tag) L4_NOTHROW;
160 
161 L4_INLINE long
162 l4_error_u(l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW;
163 
164 /*****************************************************************************
165  *** IPC results
166  *****************************************************************************/
167 
168 /**
169  * Returns whether an error occurred in send phase of an invocation.
170  * \ingroup l4_ipc_err_api
171  *
172  * \pre l4_msgtag_has_error(tag) == true
173  * \param utcb   UTCB to check.
174  *
175  * \return Boolean value.
176  */
177 L4_INLINE int l4_ipc_is_snd_error(l4_utcb_t *utcb) L4_NOTHROW;
178 
179 /**
180  * Returns whether an error occurred in receive phase of an invocation.
181  * \ingroup l4_ipc_err_api
182  *
183  * \pre l4_msgtag_has_error(tag) == true
184  * \param utcb   UTCB to check.
185  *
186  * \return Boolean value.
187  */
188 L4_INLINE int l4_ipc_is_rcv_error(l4_utcb_t *utcb) L4_NOTHROW;
189 
190 /**
191  * Get the error condition of the last invocation from the TCR.
192  * \ingroup l4_ipc_err_api
193  *
194  * \pre l4_msgtag_has_error(tag) == true
195  * \param utcb   UTCB to check.
196  *
197  * \return Error condition of type l4_ipc_tcr_error_t.
198  */
199 L4_INLINE int l4_ipc_error_code(l4_utcb_t *utcb) L4_NOTHROW;
200 
201 /**
202  * Get a negative error code for the given IPC error code.
203  * \param ipc_error_code  IPC error code as delivered by the kernel.
204  *                        (or returned by the l4_ipc_error_code() function).
205  * \return negative error code in the range of L4_EIPC_LO to L4_EIPC_HI.
206  */
207 L4_INLINE long l4_ipc_to_errno(unsigned long ipc_error_code) L4_NOTHROW;
208 
209 
210 /*****************************************************************************
211  *** IPC calls
212  *****************************************************************************/
213 
214 /**
215  * Send a message to an object (do \b not wait for a reply).
216  * \ingroup l4_ipc_api
217  *
218  * \param dest     Capability selector for the destination object. A value of
219  *                 #L4_INVALID_CAP denotes the current thread and could be used
220  *                 for sleeping without busy waiting for the time specified in
221  *                 the \c snd part of the \c timeout parameter.
222  * \param utcb     UTCB of the caller.
223  * \param tag      Descriptor for the message to be sent.
224  * \param timeout  Timeout pair (see #l4_timeout_t) only send part is relevant.
225  *
226  * \return  result tag
227  *
228  * A message is sent to the destination object. There is no receive phase
229  * included. The invoker continues working after sending the message.
230  *
231  * \attention This is a special-purpose message transfer, objects usually
232  *            support only invocation via l4_ipc_call().
233  */
234 L4_INLINE l4_msgtag_t
235 l4_ipc_send(l4_cap_idx_t dest, l4_utcb_t *utcb, l4_msgtag_t tag,
236             l4_timeout_t timeout) L4_NOTHROW;
237 
238 
239 /**
240  * Wait for an incoming message from any possible sender.
241  * \ingroup l4_ipc_api
242  *
243  * \param      utcb     UTCB of the caller.
244  * \param[out] label    Label assigned to the source object (IPC gate or IRQ).
245  * \param      timeout  Timeout pair (see #l4_timeout_t, only the receive part
246  *                      is used).
247  *
248  * \return  return tag
249  *
250  * This operation does an open wait, and therefore needs no capability to
251  * denote the possible source of a message. This means the calling thread
252  * waits for an incoming message from any possible source.
253  * There is no send phase included in this operation.
254  *
255  * The usual usage of this function is to call that function when entering a
256  * server loop in a user-level server that implements user-level objects,
257  * see also #l4_ipc_reply_and_wait().
258  */
259 L4_INLINE l4_msgtag_t
260 l4_ipc_wait(l4_utcb_t *utcb, l4_umword_t *label,
261             l4_timeout_t timeout) L4_NOTHROW;
262 
263 
264 /**
265  * Wait for a message from a specific source.
266  * \ingroup l4_ipc_api
267  *
268  * \param object   Object to receive a message from. A value of #L4_INVALID_CAP
269  *                 denotes the current thread. It could be used for sleeping
270  *                 without busy waiting for the time specified in the \c rcv
271  *                 part of the \c timeout parameter.
272  * \param timeout  Timeout pair (see #l4_timeout_t, only the receive part
273  *                 matters).
274  * \param utcb     UTCB of the caller.
275  *
276  * \return  result tag.
277  *
278  * This operation waits for a message from the specified object. Messages from
279  * other sources are not accepted by this operation. The operation does not
280  * include a send phase, this means no message is sent to the object.
281  *
282  * \note This operation is usually used to receive messages from a specific IRQ
283  *       or thread. However, it is not common to use this operation for normal
284  *       applications.
285  */
286 L4_INLINE l4_msgtag_t
287 l4_ipc_receive(l4_cap_idx_t object, l4_utcb_t *utcb,
288                l4_timeout_t timeout) L4_NOTHROW;
289 
290 /**
291  * Object call (usual invocation).
292  * \ingroup l4_ipc_api
293  *
294  * \param object   Capability selector for the object to call. A value of
295  *                 #L4_INVALID_CAP denotes the current thread and will abort
296  *                 the IPC after the time specified in the \c snd part of the
297  *                 \c timeout parameter has expired.
298  * \param utcb     UTCB of the caller.
299  * \param tag      Message tag to describe the message to be sent.
300  * \param timeout  Timeout pair for send an receive phase (see #l4_timeout_t).
301  *
302  * \return  result tag
303  *
304  * A message is sent to the object and the invoker waits for a
305  * reply from the object. Messages from other sources are not accepted.
306  * \note The send-to-receive transition needs no time, the object can reply
307  *       with a send timeout of zero.
308  */
309 L4_INLINE l4_msgtag_t
310 l4_ipc_call(l4_cap_idx_t object, l4_utcb_t *utcb, l4_msgtag_t tag,
311             l4_timeout_t timeout) L4_NOTHROW;
312 
313 
314 /**
315  * Reply and wait operation (uses the *reply* capability).
316  * \ingroup l4_ipc_api
317  *
318  * \param      utcb     UTCB of the caller.
319  * \param      tag      Describes the message to be sent as reply.
320  * \param[out] label    Label assigned to the source object of the received
321  *                      message.
322  * \param      timeout  Timeout pair (see #l4_timeout_t).
323  *
324  * \return  result tag
325  *
326  * A message is sent to the previous caller using the implicit reply
327  * capability. Afterwards the invoking thread waits for a message from any
328  * source.
329  * \note This is the standard server operation: it sends a reply to the actual
330  *       client and waits for the next incoming request, which may come from
331  *       any other client.
332  */
333 L4_INLINE l4_msgtag_t
334 l4_ipc_reply_and_wait(l4_utcb_t *utcb, l4_msgtag_t tag,
335                       l4_umword_t *label, l4_timeout_t timeout) L4_NOTHROW;
336 
337 /**
338  * Send a message and do an open wait.
339  * \ingroup l4_ipc_api
340  *
341  * \param      dest     Object to send a message to. A value of #L4_INVALID_CAP
342  *                      denotes the current thread and will abort the IPC after
343  *                      the time specified in the \c snd part of the \c timeout
344  *                      parameter has expired.
345  * \param      utcb     UTCB of the caller.
346  * \param      tag      Describes the message that shall be sent.
347  * \param[out] label    Label assigned to the source object of the receive
348  *                      phase.
349  * \param      timeout  Timeout pair (see #l4_timeout_t).
350  *
351  * \return  result tag
352  *
353  * A message is sent to the destination object and the invoking thread waits
354  * for a reply from any source.
355  *
356  * \note This is a special-purpose operation and shall not be used in general
357  *       applications.
358  */
359 L4_INLINE l4_msgtag_t
360 l4_ipc_send_and_wait(l4_cap_idx_t dest, l4_utcb_t *utcb, l4_msgtag_t tag,
361                      l4_umword_t *label, l4_timeout_t timeout) L4_NOTHROW;
362 
363 /**
364  * \defgroup l4_ipc_rt_api Realtime API
365  * \ingroup l4_ipc_api
366  * \internal
367  */
368 
369 #if 0
370 /**
371  * Wait for next period.
372  * \ingroup l4_ipc_rt_api
373  *
374  * \param utcb     UTCB of the caller.
375  * \param label    Label
376  * \param timeout  IPC timeout (see #l4_ipc_timeout).
377  *
378  * \return result tag
379  */
380 L4_INLINE l4_msgtag_t
381 l4_ipc_wait_next_period(l4_utcb_t *utcb,
382                         l4_umword_t *label,
383                         l4_timeout_t timeout);
384 
385 #endif
386 
387 /**
388  * Generic L4 object invocation.
389  * \ingroup l4_ipc_api
390  *
391  * \param      dest     Destination object. #L4_INVALID_CAP denotes the current
392  *                      thread. An IPC to the current thread will always abort
393  *                      after the specified timeout and can be used for
394  *                      sleeping without busy waiting.
395  * \param      utcb     UTCB of the caller.
396  * \param      flags    Invocation flags (see #l4_syscall_flags_t).
397  * \param      slabel   Send label if applicable (may be seen by the receiver).
398  * \param      tag      Sending message tag.
399  * \param[out] rlabel   Receiving label.
400  * \param      timeout  Timeout pair (see #l4_timeout_t).
401  *
402  * \return return tag
403  */
404 L4_ALWAYS_INLINE l4_msgtag_t
405 l4_ipc(l4_cap_idx_t dest,
406        l4_utcb_t *utcb,
407        l4_umword_t flags,
408        l4_umword_t slabel,
409        l4_msgtag_t tag,
410        l4_umword_t *rlabel,
411        l4_timeout_t timeout) L4_NOTHROW;
412 
413 /**
414  * Sleep for an amount of time.
415  * \ingroup l4_ipc_api
416  *
417  * \param timeout  Timeout pair (see #l4_timeout_t, the receive part matters).
418  *
419  * \return  error code:
420  *          - #L4_IPC_RETIMEOUT: success
421  *          - #L4_IPC_RECANCELED woken up by a different thread
422  *            (l4_thread_ex_regs()).
423  *
424  * The invoking thread waits until the timeout
425  * is expired or the wait was aborted by another thread by l4_thread_ex_regs().
426  */
427 L4_INLINE l4_msgtag_t
428 l4_ipc_sleep(l4_timeout_t timeout) L4_NOTHROW;
429 
430 /**
431  * Add a flex-page to be sent to the UTCB
432  * \ingroup l4_ipc_api
433  *
434  * \param  snd_fpage  Flex-page.
435  * \param  snd_base   Send base.
436  * \param  tag        Tag to be modified.
437  * \retval tag        Modified tag, the number of items will be increased,
438  *                    all other values in the tag will be retained.
439  *
440  * \return 0 on success, negative error code otherwise
441  */
442 L4_INLINE int
443 l4_sndfpage_add(l4_fpage_t const snd_fpage, unsigned long snd_base,
444                 l4_msgtag_t *tag) L4_NOTHROW;
445 
446 /*
447  * \internal
448  * \ingroup l4_ipc_api
449  */
450 L4_INLINE int
451 l4_sndfpage_add_u(l4_fpage_t const snd_fpage, unsigned long snd_base,
452                   l4_msgtag_t *tag, l4_utcb_t *utcb) L4_NOTHROW;
453 
454 
455 /************************************************************************
456  * Implementations
457  **********************/
458 
l4_ipc_to_errno(unsigned long ipc_error_code)459 L4_INLINE long l4_ipc_to_errno(unsigned long ipc_error_code) L4_NOTHROW
460 { return -(L4_EIPC_LO + ipc_error_code); }
461 
462 L4_INLINE l4_msgtag_t
l4_ipc_call(l4_cap_idx_t dest,l4_utcb_t * utcb,l4_msgtag_t tag,l4_timeout_t timeout)463 l4_ipc_call(l4_cap_idx_t dest, l4_utcb_t *utcb,
464             l4_msgtag_t tag,
465             l4_timeout_t timeout) L4_NOTHROW
466 {
467   return l4_ipc(dest, utcb, L4_SYSF_CALL, 0, tag, 0, timeout);
468 }
469 
470 L4_INLINE l4_msgtag_t
l4_ipc_reply_and_wait(l4_utcb_t * utcb,l4_msgtag_t tag,l4_umword_t * label,l4_timeout_t timeout)471 l4_ipc_reply_and_wait(l4_utcb_t *utcb, l4_msgtag_t tag,
472                       l4_umword_t *label,
473                       l4_timeout_t timeout) L4_NOTHROW
474 {
475   return l4_ipc(L4_INVALID_CAP, utcb, L4_SYSF_REPLY_AND_WAIT, 0, tag, label, timeout);
476 }
477 
478 L4_INLINE l4_msgtag_t
l4_ipc_send_and_wait(l4_cap_idx_t dest,l4_utcb_t * utcb,l4_msgtag_t tag,l4_umword_t * src,l4_timeout_t timeout)479 l4_ipc_send_and_wait(l4_cap_idx_t dest, l4_utcb_t *utcb,
480                      l4_msgtag_t tag,
481                      l4_umword_t *src,
482                      l4_timeout_t timeout) L4_NOTHROW
483 {
484   return l4_ipc(dest, utcb, L4_SYSF_SEND_AND_WAIT, 0, tag, src, timeout);
485 }
486 
487 L4_INLINE l4_msgtag_t
l4_ipc_send(l4_cap_idx_t dest,l4_utcb_t * utcb,l4_msgtag_t tag,l4_timeout_t timeout)488 l4_ipc_send(l4_cap_idx_t dest, l4_utcb_t *utcb,
489             l4_msgtag_t tag,
490             l4_timeout_t timeout) L4_NOTHROW
491 {
492   return l4_ipc(dest, utcb, L4_SYSF_SEND, 0, tag, 0, timeout);
493 }
494 
495 L4_INLINE l4_msgtag_t
l4_ipc_wait(l4_utcb_t * utcb,l4_umword_t * src,l4_timeout_t timeout)496 l4_ipc_wait(l4_utcb_t *utcb, l4_umword_t *src,
497             l4_timeout_t timeout) L4_NOTHROW
498 {
499   l4_msgtag_t t;
500   t.raw = 0;
501   return l4_ipc(L4_INVALID_CAP, utcb, L4_SYSF_WAIT, 0, t, src, timeout);
502 }
503 
504 L4_INLINE l4_msgtag_t
l4_ipc_receive(l4_cap_idx_t src,l4_utcb_t * utcb,l4_timeout_t timeout)505 l4_ipc_receive(l4_cap_idx_t src, l4_utcb_t *utcb,
506                l4_timeout_t timeout) L4_NOTHROW
507 {
508   l4_msgtag_t t;
509   t.raw = 0;
510   return l4_ipc(src, utcb, L4_SYSF_RECV, 0, t, 0, timeout);
511 }
512 
513 L4_INLINE l4_msgtag_t
l4_ipc_sleep(l4_timeout_t timeout)514 l4_ipc_sleep(l4_timeout_t timeout) L4_NOTHROW
515 { return l4_ipc_receive(L4_INVALID_CAP, NULL, timeout); }
516 
517 L4_INLINE l4_umword_t
l4_ipc_error(l4_msgtag_t tag,l4_utcb_t * utcb)518 l4_ipc_error(l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW
519 {
520   if (!l4_msgtag_has_error(tag))
521     return 0;
522   return l4_utcb_tcr_u(utcb)->error & L4_IPC_ERROR_MASK;
523 }
524 
525 L4_INLINE long
l4_error_u(l4_msgtag_t tag,l4_utcb_t * u)526 l4_error_u(l4_msgtag_t tag, l4_utcb_t *u) L4_NOTHROW
527 {
528   if (l4_msgtag_has_error(tag))
529     return l4_ipc_to_errno(l4_utcb_tcr_u(u)->error & L4_IPC_ERROR_MASK);
530 
531   return l4_msgtag_label(tag);
532 }
533 
534 L4_INLINE long
l4_error(l4_msgtag_t tag)535 l4_error(l4_msgtag_t tag) L4_NOTHROW
536 {
537   return l4_error_u(tag, l4_utcb());
538 }
539 
540 
l4_ipc_is_snd_error(l4_utcb_t * u)541 L4_INLINE int l4_ipc_is_snd_error(l4_utcb_t *u) L4_NOTHROW
542 { return (l4_utcb_tcr_u(u)->error & 1) == 0; }
543 
l4_ipc_is_rcv_error(l4_utcb_t * u)544 L4_INLINE int l4_ipc_is_rcv_error(l4_utcb_t *u) L4_NOTHROW
545 { return l4_utcb_tcr_u(u)->error & 1; }
546 
l4_ipc_error_code(l4_utcb_t * u)547 L4_INLINE int l4_ipc_error_code(l4_utcb_t *u) L4_NOTHROW
548 { return l4_utcb_tcr_u(u)->error & L4_IPC_ERROR_MASK; }
549 
550 
551 /*
552  * \internal
553  * \ingroup l4_ipc_api
554  */
555 L4_INLINE int
l4_sndfpage_add_u(l4_fpage_t const snd_fpage,unsigned long snd_base,l4_msgtag_t * tag,l4_utcb_t * utcb)556 l4_sndfpage_add_u(l4_fpage_t const snd_fpage, unsigned long snd_base,
557                   l4_msgtag_t *tag, l4_utcb_t *utcb) L4_NOTHROW
558 {
559   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
560   int i = l4_msgtag_words(*tag) + 2 * l4_msgtag_items(*tag);
561 
562   if (i >= L4_UTCB_GENERIC_DATA_SIZE - 1)
563     return -L4_ENOMEM;
564 
565   v->mr[i]     = snd_base | L4_ITEM_MAP | L4_ITEM_CONT;
566   v->mr[i + 1] = snd_fpage.raw;
567 
568   *tag = l4_msgtag(l4_msgtag_label(*tag), l4_msgtag_words(*tag),
569                    l4_msgtag_items(*tag) + 1, l4_msgtag_flags(*tag));
570   return 0;
571 }
572 
573 L4_INLINE int
l4_sndfpage_add(l4_fpage_t const snd_fpage,unsigned long snd_base,l4_msgtag_t * tag)574 l4_sndfpage_add(l4_fpage_t const snd_fpage, unsigned long snd_base,
575                 l4_msgtag_t *tag) L4_NOTHROW
576 {
577   return l4_sndfpage_add_u(snd_fpage, snd_base, tag, l4_utcb());
578 }
579 
580 
581 #endif /* ! __L4SYS__INCLUDE__L4API_FIASCO__IPC_H__ */
582